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;
72 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
73 grub_uint32_t g_ventoy_cpio_size
= 0;
74 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
75 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
77 ventoy_grub_param
*g_grub_param
= NULL
;
79 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
81 ventoy_img_chunk_list g_img_chunk_list
;
83 int g_wimboot_enable
= 0;
84 ventoy_img_chunk_list g_wimiso_chunk_list
;
85 char *g_wimiso_path
= NULL
;
87 static char *g_tree_script_buf
= NULL
;
88 static int g_tree_script_pos
= 0;
90 static char *g_list_script_buf
= NULL
;
91 static int g_list_script_pos
= 0;
94 void ventoy_debug(const char *fmt
, ...)
99 grub_vprintf (fmt
, args
);
103 int ventoy_is_efi_os(void)
107 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
113 static int ventoy_get_fs_type(const char *fs
)
117 return ventoy_fs_max
;
119 else if (grub_strncmp(fs
, "exfat", 5) == 0)
121 return ventoy_fs_exfat
;
123 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
125 return ventoy_fs_ntfs
;
127 else if (grub_strncmp(fs
, "ext", 3) == 0)
129 return ventoy_fs_ext
;
131 else if (grub_strncmp(fs
, "xfs", 3) == 0)
133 return ventoy_fs_xfs
;
135 else if (grub_strncmp(fs
, "udf", 3) == 0)
137 return ventoy_fs_udf
;
139 else if (grub_strncmp(fs
, "fat", 3) == 0)
141 return ventoy_fs_fat
;
144 return ventoy_fs_max
;
147 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
166 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
168 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
172 static grub_err_t
ventoy_fs_close(grub_file_t file
)
174 grub_file_close(g_old_file
);
175 grub_free(file
->data
);
183 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
187 static struct grub_fs vtoy_fs
=
192 .fs_read
= ventoy_fs_read
,
193 .fs_close
= ventoy_fs_close
,
203 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
209 file
->data
= grub_malloc(rawFile
->size
+ 4096);
215 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
216 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
218 g_old_file
= rawFile
;
220 file
->size
= rawFile
->size
+ len
;
221 file
->device
= rawFile
->device
;
223 file
->not_easily_seekable
= 1;
228 static int ventoy_check_decimal_var(const char *name
, long *value
)
230 const char *value_str
= NULL
;
232 value_str
= grub_env_get(name
);
233 if (NULL
== value_str
)
235 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
238 if (!ventoy_is_decimal(value_str
))
240 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
243 *value
= grub_strtol(value_str
, NULL
, 10);
245 return GRUB_ERR_NONE
;
248 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
252 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
255 if (0 == grub_strcmp(args
[0], "on"))
258 grub_env_set("vtdebug_flag", "debug");
263 grub_env_set("vtdebug_flag", "");
266 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
269 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
273 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
275 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
276 grub_printf(" level:\r\n");
277 grub_printf(" 01/11: busybox / (+cat log)\r\n");
278 grub_printf(" 02/12: initrd / (+cat log)\r\n");
279 grub_printf(" 03/13: hook / (+cat log)\r\n");
281 grub_printf(" debug:\r\n");
282 grub_printf(" 0: debug is on\r\n");
283 grub_printf(" 1: debug is off\r\n");
285 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
288 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
290 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
292 g_ventoy_debug_level
= 1;
295 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
298 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
303 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
305 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
308 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
313 value_long
+= grub_strtol(args
[1], NULL
, 10);
315 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
316 grub_env_set(args
[0], buf
);
318 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
321 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
336 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
339 debug("failed to open file <%s> for udf check\n", args
[0]);
343 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
345 grub_env_set(args
[1], buf
);
347 grub_file_close(file
);
353 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
361 g_wimboot_enable
= 0;
362 grub_check_free(g_wimiso_path
);
363 grub_check_free(g_wimiso_chunk_list
.chunk
);
365 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
371 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
372 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
373 if (NULL
== g_wimiso_chunk_list
.chunk
)
375 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
378 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
379 g_wimiso_chunk_list
.cur_chunk
= 0;
381 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
383 g_wimboot_enable
= 1;
384 g_wimiso_path
= grub_strdup(args
[0]);
386 grub_file_close(file
);
391 static grub_err_t
ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
408 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
411 debug("failed to open file <%s> for udf check\n", args
[0]);
415 #ifdef GRUB_MACHINE_EFI
416 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
418 buf
= (char *)grub_malloc(file
->size
);
421 grub_file_read(file
, buf
, file
->size
);
423 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
424 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
425 grub_env_set(name
, value
);
427 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
428 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
429 grub_env_set(name
, value
);
431 grub_file_close(file
);
437 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
446 if (args
[0][0] == '1')
448 grub_iso9660_set_nojoliet(1);
452 grub_iso9660_set_nojoliet(0);
458 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
463 grub_uint8_t buf
[32];
474 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
477 debug("failed to open file <%s> for udf check\n", args
[0]);
481 for (i
= 16; i
< 32; i
++)
483 grub_file_seek(file
, i
* 2048);
484 grub_file_read(file
, buf
, sizeof(buf
));
492 grub_file_seek(file
, i
* 2048);
493 grub_file_read(file
, buf
, sizeof(buf
));
495 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
498 grub_file_seek(file
, i
* 2048);
499 grub_file_read(file
, buf
, sizeof(buf
));
501 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
502 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
508 grub_file_close(file
);
510 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
515 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
517 long value_long1
= 0;
518 long value_long2
= 0;
520 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
522 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
525 value_long1
= grub_strtol(args
[0], NULL
, 10);
526 value_long2
= grub_strtol(args
[2], NULL
, 10);
528 if (0 == grub_strcmp(args
[1], "eq"))
530 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
532 else if (0 == grub_strcmp(args
[1], "ne"))
534 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
536 else if (0 == grub_strcmp(args
[1], "gt"))
538 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
540 else if (0 == grub_strcmp(args
[1], "lt"))
542 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
544 else if (0 == grub_strcmp(args
[1], "ge"))
546 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
548 else if (0 == grub_strcmp(args
[1], "le"))
550 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
554 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
560 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
567 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
570 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
571 pos
= grub_strstr(buf
, ",");
577 grub_env_set(args
[1], buf
);
579 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
582 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
588 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
594 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
597 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
599 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
600 if (0 == grub_script_execute_sourcecode(buf
))
602 debug("file %s exist, ventoy_compatible YES\n", buf
);
603 grub_env_set("ventoy_compatible", "YES");
604 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
608 debug("file %s NOT exist\n", buf
);
612 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
613 pos
= grub_strstr(buf
, ")");
619 disk
= grub_disk_open(buf
);
622 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
623 grub_disk_close(disk
);
625 g_img_swap_tmp_buf
[703] = 0;
626 for (i
= 319; i
< 703; i
++)
628 if (g_img_swap_tmp_buf
[i
] == 'V' &&
629 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
631 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
632 grub_env_set("ventoy_compatible", "YES");
633 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
639 debug("failed to open disk <%s>\n", buf
);
642 grub_env_set("ventoy_compatible", "NO");
643 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
646 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
652 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
657 if (grub_islower(c1
))
662 if (grub_islower(c2
))
676 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
678 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
680 grub_memcpy(img1
, img2
, sizeof(img_info
));
681 img1
->next
= g_img_swap_tmp
.next
;
682 img1
->prev
= g_img_swap_tmp
.prev
;
684 g_img_swap_tmp
.next
= img2
->next
;
685 g_img_swap_tmp
.prev
= img2
->prev
;
686 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
689 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
693 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
698 for (i
= 0; i
< namelen
; i
++)
700 if (filename
[i
] == ' ' || filename
[i
] == '\t')
705 if ((grub_uint8_t
)(filename
[i
]) >= 127)
714 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
718 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
728 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
736 img_iterator_node
*tmp
;
737 img_iterator_node
*new_node
;
738 img_iterator_node
*node
= (img_iterator_node
*)data
;
740 len
= grub_strlen(filename
);
744 if ((len
== 1 && filename
[0] == '.') ||
745 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
750 if (!ventoy_img_name_valid(filename
, len
))
755 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
760 new_node
= grub_zalloc(sizeof(img_iterator_node
));
763 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
765 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
768 debug("Directory %s ignored...\n", new_node
->dir
);
773 new_node
->tail
= node
->tail
;
775 new_node
->parent
= node
;
776 if (!node
->firstchild
)
778 node
->firstchild
= new_node
;
781 if (g_img_iterator_tail
)
783 g_img_iterator_tail
->next
= new_node
;
784 g_img_iterator_tail
= new_node
;
788 g_img_iterator_head
.next
= new_node
;
789 g_img_iterator_tail
= new_node
;
795 debug("Find a file %s\n", filename
);
801 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
805 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
814 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
819 img
= grub_zalloc(sizeof(img_info
));
823 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
825 for (i
= 0; i
< (int)len
; i
++)
827 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
834 grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
836 img
->size
= info
->size
;
839 img
->size
= ventoy_grub_get_file_size("%s/%s", g_iso_path
, img
->path
);
842 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
844 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
849 if (g_ventoy_img_list
)
851 tail
= *(node
->tail
);
857 g_ventoy_img_list
= img
;
860 img
->id
= g_ventoy_img_count
;
862 if (node
&& NULL
== node
->firstiso
)
864 node
->firstiso
= img
;
875 *((img_info
**)(node
->tail
)) = img
;
876 g_ventoy_img_count
++;
878 img
->alias
= ventoy_plugin_get_menu_alias(img
->path
);
880 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
887 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
889 int len
= GRUB_UINT_MAX
;
890 const char *value
= NULL
;
893 char guidstr
[32] = {0};
894 ventoy_guid guid
= VENTOY_GUID
;
895 const char *fmt1
= NULL
;
896 const char *fmt2
= NULL
;
897 const char *fmt3
= NULL
;
898 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
899 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
900 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
901 const char fmtcode
[]={
902 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
903 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
904 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
905 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
906 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
907 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
910 grub_memset(name
, 0, sizeof(name
));
911 puint
[0] = grub_swap_bytes32(0x56454e54);
912 puint
[3] = grub_swap_bytes32(0x4f4e0000);
913 puint
[2] = grub_swap_bytes32(0x45525349);
914 puint
[1] = grub_swap_bytes32(0x4f595f56);
915 value
= ventoy_get_env(name
);
917 grub_memset(name
, 0, sizeof(name
));
918 puint
[1] = grub_swap_bytes32(0x5f544f50);
919 puint
[0] = grub_swap_bytes32(0x56544c45);
920 fmt1
= ventoy_get_env(name
);
926 grub_memset(name
, 0, sizeof(name
));
927 puint
[1] = grub_swap_bytes32(0x5f4c4654);
928 puint
[0] = grub_swap_bytes32(0x56544c45);
929 fmt2
= ventoy_get_env(name
);
931 grub_memset(name
, 0, sizeof(name
));
932 puint
[1] = grub_swap_bytes32(0x5f434c52);
933 puint
[0] = grub_swap_bytes32(0x56544c45);
934 fmt3
= ventoy_get_env(name
);
936 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
938 #if defined (GRUB_MACHINE_EFI)
939 puint2
[0] = grub_swap_bytes32(0x55454649);
941 puint2
[0] = grub_swap_bytes32(0x42494f53);
944 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
945 #pragma GCC diagnostic push
946 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
947 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
948 fmt1
? fmt1
: fmtdata
,
949 fmt2
? fmt2
: fmtdata
+ 4,
950 value
? value
: "", plat
, guidstr
,
951 fmt3
? fmt3
: fmtdata
+ 6);
952 #pragma GCC diagnostic pop
954 grub_memset(name
, 0, sizeof(name
));
955 puint
[0] = grub_swap_bytes32(0x76746f79);
956 puint
[2] = grub_swap_bytes32(0x656e7365);
957 puint
[1] = grub_swap_bytes32(0x5f6c6963);
958 ventoy_set_env(name
, guidstr
);
963 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
965 img_info
*minimg
= NULL
;
966 img_info
*img
= (img_info
*)(node
->firstiso
);
968 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
970 if (img
->select
== 0 && (NULL
== minimg
|| grub_strcmp(img
->name
, minimg
->name
) < 0))
985 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
987 img_iterator_node
*Minchild
= NULL
;
988 img_iterator_node
*child
= node
->firstchild
;
990 while (child
&& child
->parent
== node
)
992 if (child
->select
== 0 && (NULL
== Minchild
|| grub_strcmp(child
->dir
, Minchild
->dir
) < 0))
1001 Minchild
->select
= 1;
1007 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1011 img_iterator_node
*child
= NULL
;
1013 if (node
->isocnt
== 0 || node
->done
== 1)
1018 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1020 offset
= node
->parent
->dirlen
;
1023 if (node
== &g_img_iterator_head
)
1025 if (g_default_menu_mode
== 0)
1027 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1028 "menuentry \"%-10s [Return to ListView]\" VTOY_RET {\n "
1029 " echo 'return ...' \n"
1035 node
->dir
[node
->dirlen
- 1] = 0;
1036 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1037 "submenu \"%-10s [%s]\" {\n",
1038 "DIR", node
->dir
+ offset
);
1040 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1041 "menuentry \"%-10s [../]\" VTOY_RET {\n "
1042 " echo 'return ...' \n"
1046 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1048 ventoy_dynamic_tree_menu(child
);
1051 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1053 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1054 "menuentry \"%-10s %s%s\" --id=\"VID_%d\" {\n"
1057 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1058 img
->unsupport
? "[unsupported] " : "",
1059 img
->alias
? img
->alias
: img
->name
, img
->id
,
1060 (img
->type
== img_type_iso
) ? "iso" : "wim",
1061 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1064 if (node
!= &g_img_iterator_head
)
1066 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1073 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1077 grub_device_t dev
= NULL
;
1078 img_info
*cur
= NULL
;
1079 img_info
*tail
= NULL
;
1080 const char *strdata
= NULL
;
1081 char *device_name
= NULL
;
1083 img_iterator_node
*node
= NULL
;
1084 img_iterator_node
*tmp
= NULL
;
1090 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1093 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1095 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1098 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1099 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1101 g_filt_dot_underscore_file
= 1;
1104 device_name
= grub_file_get_device_name(args
[0]);
1110 g_enum_dev
= dev
= grub_device_open(device_name
);
1116 g_enum_fs
= fs
= grub_fs_probe(dev
);
1122 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1124 debug("unsupported fs:<%s>\n", fs
->name
);
1125 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1129 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1130 if (strdata
&& strdata
[0] == '1')
1132 g_default_menu_mode
= 1;
1135 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1137 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1139 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1140 if (strdata
&& strdata
[0] == '/')
1142 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1143 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1145 g_img_iterator_head
.dir
[len
++] = '/';
1147 g_img_iterator_head
.dirlen
= len
;
1151 g_img_iterator_head
.dirlen
= 1;
1152 grub_strcpy(g_img_iterator_head
.dir
, "/");
1155 g_img_iterator_head
.tail
= &tail
;
1157 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1159 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1162 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1164 ventoy_dynamic_tree_menu(node
);
1168 node
= g_img_iterator_head
.next
;
1176 /* sort image list by image name */
1177 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1179 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1181 if (ventoy_cmp_img(cur
, tail
) > 0)
1183 ventoy_swap_img(cur
, tail
);
1188 if (g_default_menu_mode
== 1)
1190 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1191 "menuentry \"%s [Return to TreeView]\" VTOY_RET {\n "
1192 " echo 'return ...' \n"
1196 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1198 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1199 "menuentry \"%s%s\" --id=\"VID_%d\" {\n"
1202 cur
->unsupport
? "[unsupported] " : "",
1203 cur
->alias
? cur
->alias
: cur
->name
, cur
->id
,
1204 (cur
->type
== img_type_iso
) ? "iso" : "wim",
1205 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1207 g_list_script_buf
[g_list_script_pos
] = 0;
1209 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1210 grub_env_set(args
[1], buf
);
1214 check_free(device_name
, grub_free
);
1215 check_free(dev
, grub_device_close
);
1217 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1221 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1223 img_info
*next
= NULL
;
1224 img_info
*cur
= g_ventoy_img_list
;
1237 g_ventoy_img_list
= NULL
;
1238 g_ventoy_img_count
= 0;
1240 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1243 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1246 img_info
*cur
= g_ventoy_img_list
;
1250 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1252 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1255 img_id
= grub_strtol(args
[0], NULL
, 10);
1256 if (img_id
>= g_ventoy_img_count
)
1258 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1261 debug("Find image %ld name \n", img_id
);
1263 while (cur
&& img_id
> 0)
1271 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
1274 debug("image name is %s\n", cur
->name
);
1276 grub_env_set(args
[1], cur
->name
);
1278 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1281 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1285 const char *id
= NULL
;
1286 img_info
*cur
= g_ventoy_img_list
;
1292 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
1295 id
= grub_env_get("chosen");
1297 pos
= grub_strstr(id
, "VID_");
1300 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
1304 img_id
= (int)grub_strtoul(id
, NULL
, 10);
1309 if (img_id
== cur
->id
)
1318 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
1321 grub_env_set(args
[0], cur
->path
);
1323 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1326 static int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
1333 device_name
= grub_file_get_device_name(filename
);
1345 pos2
= grub_strstr(pos
, ",");
1348 pos2
= grub_strstr(pos
, ")");
1356 disk
= grub_disk_open(pos
);
1359 grub_disk_read(disk
, 0, 0x180, 16, guid
);
1360 grub_disk_close(disk
);
1367 grub_free(device_name
);
1371 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
1373 eltorito_descriptor desc
;
1375 grub_memset(&desc
, 0, sizeof(desc
));
1376 grub_file_seek(file
, 17 * 2048);
1377 grub_file_read(file
, &desc
, sizeof(desc
));
1379 if (desc
.type
!= 0 || desc
.version
!= 1)
1384 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
1385 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
1393 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
1396 grub_uint8_t buf
[512];
1398 grub_file_seek(file
, sector
* 2048);
1399 grub_file_read(file
, buf
, sizeof(buf
));
1401 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
1403 debug("%s efi eltorito in Validation Entry\n", file
->name
);
1407 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
1409 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
1411 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1416 debug("%s does not contain efi eltorito\n", file
->name
);
1420 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1423 const char *fs
= NULL
;
1425 grub_uint8_t chksum
= 0;
1428 disk
= file
->device
->disk
;
1429 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1431 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1432 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1433 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
1435 pos
= grub_strstr(file
->name
, "/");
1441 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1443 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1445 param
->vtoy_img_size
= file
->size
;
1447 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1448 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1450 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
1452 fs
= ventoy_get_env("ventoy_fs_probe");
1453 if (fs
&& grub_strcmp(fs
, "udf") == 0)
1455 param
->vtoy_reserved
[3] = 1;
1458 /* calculate checksum */
1459 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1461 chksum
+= *((grub_uint8_t
*)param
+ i
);
1463 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1468 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1470 grub_uint32_t i
= 0;
1471 grub_uint64_t total
= 0;
1472 ventoy_img_chunk
*chunk
= NULL
;
1474 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1476 chunk
= chunklist
->chunk
+ i
;
1478 if (chunk
->disk_start_sector
<= start
)
1480 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
1484 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
1487 if (total
!= ((file
->size
+ 511) / 512))
1489 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
1496 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1499 grub_uint32_t i
= 0;
1500 grub_uint32_t sector
= 0;
1501 grub_uint32_t count
= 0;
1502 grub_off_t size
= 0;
1503 grub_off_t read
= 0;
1505 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
1506 if (fs_type
== ventoy_fs_exfat
)
1508 grub_fat_get_file_chunk(start
, file
, chunklist
);
1510 else if (fs_type
== ventoy_fs_ext
)
1512 grub_ext_get_file_chunk(start
, file
, chunklist
);
1516 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
1517 file
->read_hook_data
= chunklist
;
1519 for (size
= file
->size
; size
> 0; size
-= read
)
1521 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
1522 grub_file_read(file
, NULL
, read
);
1525 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
1527 chunklist
->chunk
[i
].disk_start_sector
+= start
;
1528 chunklist
->chunk
[i
].disk_end_sector
+= start
;
1531 if (ventoy_fs_udf
== fs_type
)
1533 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1535 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
1536 chunklist
->chunk
[i
].img_start_sector
= sector
;
1537 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
1546 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1550 grub_disk_addr_t start
;
1555 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1558 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1561 if (g_img_chunk_list
.chunk
)
1563 grub_free(g_img_chunk_list
.chunk
);
1566 /* get image chunk data */
1567 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
1568 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1569 if (NULL
== g_img_chunk_list
.chunk
)
1571 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1574 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
1575 g_img_chunk_list
.cur_chunk
= 0;
1577 start
= file
->device
->disk
->partition
->start
;
1579 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
1581 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
1582 grub_file_close(file
);
1586 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
1589 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
1590 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1593 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1598 char configfile
[128];
1599 install_template
*node
= NULL
;
1605 debug("select auto installation %d\n", argc
);
1612 node
= ventoy_plugin_find_install_template(args
[0]);
1615 debug("Install template not found for %s\n", args
[0]);
1619 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1625 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
1626 " echo %s\n}\n", "123");
1628 for (i
= 0; i
< node
->templatenum
; i
++)
1630 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1632 node
->templatepath
[i
].path
);
1635 g_ventoy_menu_esc
= 1;
1636 g_ventoy_suppress_esc
= 1;
1638 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1639 grub_script_execute_sourcecode(configfile
);
1641 g_ventoy_menu_esc
= 0;
1642 g_ventoy_suppress_esc
= 0;
1646 node
->cursel
= g_ventoy_last_entry
- 1;
1648 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1651 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1656 char configfile
[128];
1657 persistence_config
*node
;
1663 debug("select persistece %d\n", argc
);
1670 node
= ventoy_plugin_find_persistent(args
[0]);
1673 debug("Persistence image not found for %s\n", args
[0]);
1677 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1683 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
1684 " echo %s\n}\n", "123");
1686 for (i
= 0; i
< node
->backendnum
; i
++)
1688 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1690 node
->backendpath
[i
].path
);
1694 g_ventoy_menu_esc
= 1;
1695 g_ventoy_suppress_esc
= 1;
1697 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1698 grub_script_execute_sourcecode(configfile
);
1700 g_ventoy_menu_esc
= 0;
1701 g_ventoy_suppress_esc
= 0;
1705 node
->cursel
= g_ventoy_last_entry
- 1;
1707 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1710 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1713 ventoy_img_chunk
*cur
;
1719 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
1721 cur
= g_img_chunk_list
.chunk
+ i
;
1722 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1723 cur
->img_start_sector
, cur
->img_end_sector
,
1724 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
1728 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1731 #ifdef GRUB_MACHINE_EFI
1732 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1740 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1743 ulong chain_len
= 0;
1744 char *chain_data
= NULL
;
1745 char *relocator_addr
= NULL
;
1746 grub_relocator_chunk_t ch
;
1747 struct grub_relocator
*relocator
= NULL
;
1748 char envbuf
[64] = { 0 };
1759 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
1760 chain_len
= grub_strtoul(args
[1], NULL
, 10);
1762 relocator
= grub_relocator_new ();
1765 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
1769 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
1770 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1774 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
1775 grub_relocator_unload (relocator
);
1779 relocator_addr
= get_virtual_current_address(ch
);
1781 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
1783 grub_relocator_unload (relocator
);
1785 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
1786 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
1788 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1792 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1796 ventoy_img_chunk_list chunklist
;
1801 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1804 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1807 /* get image chunk data */
1808 grub_memset(&chunklist
, 0, sizeof(chunklist
));
1809 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1810 if (NULL
== chunklist
.chunk
)
1812 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1815 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
1816 chunklist
.cur_chunk
= 0;
1818 ventoy_get_block_list(file
, &chunklist
, 0);
1820 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
1822 grub_printf("########## UNSUPPORTED ###############\n");
1825 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
1827 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1829 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1830 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
1833 grub_printf("\n==================================\n");
1835 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1837 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
1838 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
1839 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
1840 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1841 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
1845 grub_free(chunklist
.chunk
);
1846 grub_file_close(file
);
1848 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1851 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1854 ventoy_grub_param_file_replace
*replace
= NULL
;
1862 replace
= &(g_grub_param
->file_replace
);
1863 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
1865 replace
->old_name_cnt
= 0;
1866 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
1868 replace
->old_name_cnt
++;
1869 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
1872 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
1875 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1878 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1886 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1887 grub_printf("%s", g_list_script_buf
);
1891 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1892 grub_printf("%s", g_tree_script_buf
);
1898 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1900 img_info
*cur
= g_ventoy_img_list
;
1908 grub_printf("path:<%s>\n", cur
->path
);
1909 grub_printf("name:<%s>\n\n", cur
->name
);
1916 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1927 file
= grub_file_open("(hd0,1)/ventoy/ventoy.disk.img.xz", GRUB_FILE_TYPE_NONE
);
1930 grub_printf("Open File OK (size:%llu)\n", (ulonglong
)file
->size
);
1932 buf
= grub_malloc(file
->size
);
1933 grub_file_read(file
, buf
, file
->size
);
1935 grub_file_close(file
);
1937 grub_snprintf(name
, sizeof(name
), "mem:0x%llx:size:%llu", (ulonglong
)(ulong
)buf
, (ulonglong
)file
->size
);
1938 grub_printf("<%s>\n", name
);
1943 ventoy_plugin_dump_auto_install();
1948 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1954 ventoy_plugin_dump_persistence();
1959 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1970 if (args
[0][0] == '0')
1972 return g_ventoy_memdisk_mode
? 0 : 1;
1974 else if (args
[0][0] == '1')
1976 return g_ventoy_iso_raw
? 0 : 1;
1978 else if (args
[0][0] == '2')
1980 return g_ventoy_iso_uefi_drv
? 0 : 1;
1986 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1988 static int configfile_mode
= 0;
1989 char memfile
[128] = {0};
1996 * args[0]: 0:normal 1:configfile
1997 * args[1]: 0:list_buf 1:tree_buf
2002 debug("Invalid argc %d\n", argc
);
2006 if (args
[0][0] == '0')
2008 if (args
[1][0] == '0')
2010 grub_script_execute_sourcecode(g_list_script_buf
);
2014 grub_script_execute_sourcecode(g_tree_script_buf
);
2019 if (configfile_mode
)
2021 debug("Now already in F3 mode %d\n", configfile_mode
);
2025 if (args
[1][0] == '0')
2027 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2028 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2032 g_ventoy_last_entry
= -1;
2033 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2034 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2037 configfile_mode
= 1;
2038 grub_script_execute_sourcecode(memfile
);
2039 configfile_mode
= 0;
2045 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2056 g_ventoy_case_insensitive
= 1;
2057 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2058 g_ventoy_case_insensitive
= 0;
2064 grub_file_close(file
);
2070 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2075 const char *isopath
= NULL
;
2077 ventoy_mbr_head mbr
;
2084 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2087 isopath
= grub_env_get("iso_path");
2090 debug("isopath is null %p\n", isopath
);
2094 debug("isopath is %s\n", isopath
);
2096 for (id
= 0; id
< 30 && (find
== 0); id
++)
2098 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2099 if (grub_strstr(isopath
, hdname
))
2101 debug("skip %s ...\n", hdname
);
2105 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2107 disk
= grub_disk_open(hdname
);
2110 debug("%s not exist\n", hdname
);
2114 grub_memset(&mbr
, 0, sizeof(mbr
));
2115 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2117 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2119 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2120 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2123 grub_env_set(args
[0], hdname
);
2127 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2131 debug("read %s failed\n", hdname
);
2134 grub_disk_close(disk
);
2140 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
2142 grub_uint64_t size
= 0;
2145 char fullpath
[256] = {0};
2148 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2151 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
2154 debug("grub_file_open failed <%s>\n", fullpath
);
2160 grub_file_close(file
);
2164 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
2168 char fullpath
[256] = {0};
2171 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2174 file
= grub_file_open(fullpath
, type
);
2177 debug("grub_file_open failed <%s>\n", fullpath
);
2184 int ventoy_is_file_exist(const char *fmt
, ...)
2189 char buf
[256] = {0};
2191 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
2195 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2198 grub_strncpy(pos
+ len
, " ]", 2);
2200 debug("script exec %s\n", buf
);
2202 if (0 == grub_script_execute_sourcecode(buf
))
2210 static int ventoy_env_init(void)
2214 grub_env_set("vtdebug_flag", "");
2215 grub_env_export("vtdebug_flag");
2219 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2220 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2222 ventoy_filt_register(0, ventoy_wrapper_open
);
2224 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
2227 g_grub_param
->grub_env_get
= grub_env_get
;
2228 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
2229 grub_env_set("env_param", buf
);
2235 static cmd_para ventoy_cmds
[] =
2237 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
2238 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2239 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2240 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
2241 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
2242 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
2243 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
2244 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
2245 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
2246 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
2247 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
2248 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
2249 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
2250 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
2251 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
2252 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
2253 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
2254 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
2255 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
2256 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
2257 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
2258 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
2259 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
2260 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
2262 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
2263 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
2264 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
2265 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem
, 0, NULL
, "", "", NULL
},
2267 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2268 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2269 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
2270 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
2271 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
2272 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
2273 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
2274 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
2275 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
2276 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
2278 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
2279 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
2280 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
2281 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
2282 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
2283 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
2284 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
2286 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
2287 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
2288 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
2289 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
2292 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
2293 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
2299 GRUB_MOD_INIT(ventoy
)
2302 cmd_para
*cur
= NULL
;
2306 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2308 cur
= ventoy_cmds
+ i
;
2309 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
2310 cur
->summary
, cur
->description
, cur
->parser
);
2314 GRUB_MOD_FINI(ventoy
)
2318 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2320 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);