]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
experimental support for loongson mips64el uefi
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy.c
1 /******************************************************************************
2 * ventoy.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20
21 #include <grub/types.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/err.h>
25 #include <grub/dl.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>
35 #include <grub/net.h>
36 #include <grub/misc.h>
37 #include <grub/kernel.h>
38 #ifdef GRUB_MACHINE_EFI
39 #include <grub/efi/api.h>
40 #include <grub/efi/efi.h>
41 #endif
42 #include <grub/time.h>
43 #include <grub/video.h>
44 #include <grub/acpi.h>
45 #include <grub/charset.h>
46 #include <grub/crypto.h>
47 #include <grub/lib/crc.h>
48 #include <grub/ventoy.h>
49 #include "ventoy_def.h"
50 #include "miniz.h"
51
52 GRUB_MOD_LICENSE ("GPLv3+");
53
54 int g_ventoy_debug = 0;
55 static int g_efi_os = 0xFF;
56 initrd_info *g_initrd_img_list = NULL;
57 initrd_info *g_initrd_img_tail = NULL;
58 int g_initrd_img_count = 0;
59 int g_valid_initrd_count = 0;
60 int g_default_menu_mode = 0;
61 int g_filt_dot_underscore_file = 0;
62 int g_sort_case_sensitive = 0;
63 int g_tree_view_menu_style = 0;
64 static grub_file_t g_old_file;
65 static int g_ventoy_last_entry_back;
66 static grub_uint32_t g_ventoy_plat_data;
67
68 char g_iso_path[256];
69 char g_img_swap_tmp_buf[1024];
70 img_info g_img_swap_tmp;
71 img_info *g_ventoy_img_list = NULL;
72
73 int g_ventoy_img_count = 0;
74
75 grub_device_t g_enum_dev = NULL;
76 grub_fs_t g_enum_fs = NULL;
77 int g_img_max_search_level = -1;
78 img_iterator_node g_img_iterator_head;
79 img_iterator_node *g_img_iterator_tail = NULL;
80
81 grub_uint8_t g_ventoy_break_level = 0;
82 grub_uint8_t g_ventoy_debug_level = 0;
83 grub_uint8_t g_ventoy_chain_type = 0;
84
85 grub_uint8_t *g_ventoy_cpio_buf = NULL;
86 grub_uint32_t g_ventoy_cpio_size = 0;
87 cpio_newc_header *g_ventoy_initrd_head = NULL;
88 grub_uint8_t *g_ventoy_runtime_buf = NULL;
89
90 int g_plugin_image_list = 0;
91
92 ventoy_grub_param *g_grub_param = NULL;
93
94 ventoy_guid g_ventoy_guid = VENTOY_GUID;
95
96 ventoy_img_chunk_list g_img_chunk_list;
97
98 int g_wimboot_enable = 0;
99 ventoy_img_chunk_list g_wimiso_chunk_list;
100 char *g_wimiso_path = NULL;
101
102 int g_vhdboot_enable = 0;
103
104 grub_uint64_t g_conf_replace_offset = 0;
105 grub_uint64_t g_svd_replace_offset = 0;
106 conf_replace *g_conf_replace_node = NULL;
107 grub_uint8_t *g_conf_replace_new_buf = NULL;
108 int g_conf_replace_new_len = 0;
109 int g_conf_replace_new_len_align = 0;
110
111 ventoy_gpt_info *g_ventoy_part_info = NULL;
112 grub_uint64_t g_ventoy_disk_size = 0;
113
114 static char *g_tree_script_buf = NULL;
115 static int g_tree_script_pos = 0;
116
117 static char *g_list_script_buf = NULL;
118 static int g_list_script_pos = 0;
119
120 static char *g_part_list_buf = NULL;
121 static int g_part_list_pos = 0;
122
123 static int g_video_mode_max = 0;
124 static int g_video_mode_num = 0;
125 static ventoy_video_mode *g_video_mode_list = NULL;
126
127 static int g_enumerate_time_checked = 0;
128 static grub_uint64_t g_enumerate_start_time_ms;
129 static grub_uint64_t g_enumerate_finish_time_ms;
130
131 static const char *g_menu_class[] =
132 {
133 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
134 };
135
136 static const char *g_menu_prefix[] =
137 {
138 "iso", "wim", "efi", "img", "vhd", "vtoy"
139 };
140
141 void ventoy_debug(const char *fmt, ...)
142 {
143 va_list args;
144
145 va_start (args, fmt);
146 grub_vprintf (fmt, args);
147 va_end (args);
148 }
149
150 void ventoy_debug_dump_guid(const char *prefix, grub_uint8_t *guid)
151 {
152 int i;
153
154 if (!g_ventoy_debug)
155 {
156 return;
157 }
158
159 debug("%s", prefix);
160 for (i = 0; i < 16; i++)
161 {
162 grub_printf("%02x ", guid[i]);
163 }
164 grub_printf("\n");
165 }
166
167 int ventoy_is_efi_os(void)
168 {
169 if (g_efi_os > 1)
170 {
171 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
172 }
173
174 return g_efi_os;
175 }
176
177 static int ventoy_get_fs_type(const char *fs)
178 {
179 if (NULL == fs)
180 {
181 return ventoy_fs_max;
182 }
183 else if (grub_strncmp(fs, "exfat", 5) == 0)
184 {
185 return ventoy_fs_exfat;
186 }
187 else if (grub_strncmp(fs, "ntfs", 4) == 0)
188 {
189 return ventoy_fs_ntfs;
190 }
191 else if (grub_strncmp(fs, "ext", 3) == 0)
192 {
193 return ventoy_fs_ext;
194 }
195 else if (grub_strncmp(fs, "xfs", 3) == 0)
196 {
197 return ventoy_fs_xfs;
198 }
199 else if (grub_strncmp(fs, "udf", 3) == 0)
200 {
201 return ventoy_fs_udf;
202 }
203 else if (grub_strncmp(fs, "fat", 3) == 0)
204 {
205 return ventoy_fs_fat;
206 }
207
208 return ventoy_fs_max;
209 }
210
211 static int ventoy_string_check(const char *str, grub_char_check_func check)
212 {
213 if (!str)
214 {
215 return 0;
216 }
217
218 for ( ; *str; str++)
219 {
220 if (!check(*str))
221 {
222 return 0;
223 }
224 }
225
226 return 1;
227 }
228
229
230 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
231 {
232 grub_memcpy(buf, (char *)file->data + file->offset, len);
233 return len;
234 }
235
236 static grub_err_t ventoy_fs_close(grub_file_t file)
237 {
238 grub_file_close(g_old_file);
239 grub_free(file->data);
240
241 file->device = 0;
242 file->name = 0;
243
244 return 0;
245 }
246
247 static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg)
248 {
249 int i;
250
251 (void)hook_arg;
252
253 if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
254 {
255 return 0;
256 }
257
258 for (i = 0; i < g_video_mode_num; i++)
259 {
260 if (g_video_mode_list[i].width == info->width &&
261 g_video_mode_list[i].height == info->height &&
262 g_video_mode_list[i].bpp == info->bpp)
263 {
264 return 0;
265 }
266 }
267
268 g_video_mode_list[g_video_mode_num].width = info->width;
269 g_video_mode_list[g_video_mode_num].height = info->height;
270 g_video_mode_list[g_video_mode_num].bpp = info->bpp;
271 g_video_mode_num++;
272
273 if (g_video_mode_num == g_video_mode_max)
274 {
275 g_video_mode_max *= 2;
276 g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode));
277 }
278
279 return 0;
280 }
281
282 static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2)
283 {
284 if (v1->bpp == v2->bpp)
285 {
286 if (v1->width == v2->width)
287 {
288 if (v1->height == v2->height)
289 {
290 return 0;
291 }
292 else
293 {
294 return (v1->height < v2->height) ? -1 : 1;
295 }
296 }
297 else
298 {
299 return (v1->width < v2->width) ? -1 : 1;
300 }
301 }
302 else
303 {
304 return (v1->bpp < v2->bpp) ? -1 : 1;
305 }
306 }
307
308 static int ventoy_enum_video_mode(void)
309 {
310 int i, j;
311 grub_video_adapter_t adapter;
312 grub_video_driver_id_t id;
313 ventoy_video_mode mode;
314
315 g_video_mode_num = 0;
316 g_video_mode_max = 1024;
317 g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max);
318 if (!g_video_mode_list)
319 {
320 return 0;
321 }
322
323 #ifdef GRUB_MACHINE_PCBIOS
324 grub_dl_load ("vbe");
325 #endif
326
327 id = grub_video_get_driver_id ();
328
329 FOR_VIDEO_ADAPTERS (adapter)
330 {
331 if (!adapter->iterate ||
332 (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE ||
333 adapter->init() != GRUB_ERR_NONE)))
334 {
335 continue;
336 }
337
338 adapter->iterate(ventoy_video_hook, NULL);
339
340 if (adapter->id != id)
341 {
342 adapter->fini();
343 }
344 }
345
346 /* sort video mode */
347 for (i = 0; i < g_video_mode_num; i++)
348 for (j = i + 1; j < g_video_mode_num; j++)
349 {
350 if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0)
351 {
352 grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode));
353 grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode));
354 grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode));
355 }
356 }
357
358 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
359 }
360
361 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
362 {
363 int len;
364 grub_file_t file;
365 static struct grub_fs vtoy_fs =
366 {
367 .name = "vtoy",
368 .fs_dir = 0,
369 .fs_open = 0,
370 .fs_read = ventoy_fs_read,
371 .fs_close = ventoy_fs_close,
372 .fs_label = 0,
373 .next = 0
374 };
375
376 if (type != 52)
377 {
378 return rawFile;
379 }
380
381 file = (grub_file_t)grub_zalloc(sizeof (*file));
382 if (!file)
383 {
384 return 0;
385 }
386
387 file->data = grub_malloc(rawFile->size + 4096);
388 if (!file->data)
389 {
390 return 0;
391 }
392
393 grub_file_read(rawFile, file->data, rawFile->size);
394 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
395
396 g_old_file = rawFile;
397
398 file->size = rawFile->size + len;
399 file->device = rawFile->device;
400 file->fs = &vtoy_fs;
401 file->not_easily_seekable = 1;
402
403 return file;
404 }
405
406 static int ventoy_check_decimal_var(const char *name, long *value)
407 {
408 const char *value_str = NULL;
409
410 value_str = grub_env_get(name);
411 if (NULL == value_str)
412 {
413 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
414 }
415
416 if (!ventoy_is_decimal(value_str))
417 {
418 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
419 }
420
421 *value = grub_strtol(value_str, NULL, 10);
422
423 return GRUB_ERR_NONE;
424 }
425
426 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
427 {
428 if (argc != 1)
429 {
430 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
431 }
432
433 if (0 == grub_strcmp(args[0], "on"))
434 {
435 g_ventoy_debug = 1;
436 grub_env_set("vtdebug_flag", "debug");
437 }
438 else
439 {
440 g_ventoy_debug = 0;
441 grub_env_set("vtdebug_flag", "");
442 }
443
444 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
445 }
446
447 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
448 {
449 (void)ctxt;
450
451 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
452 {
453 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
454 grub_printf(" level:\r\n");
455 grub_printf(" 01/11: busybox / (+cat log)\r\n");
456 grub_printf(" 02/12: initrd / (+cat log)\r\n");
457 grub_printf(" 03/13: hook / (+cat log)\r\n");
458 grub_printf("\r\n");
459 grub_printf(" debug:\r\n");
460 grub_printf(" 0: debug is off\r\n");
461 grub_printf(" 1: debug is on\r\n");
462 grub_printf("\r\n");
463 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
464 }
465
466 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
467
468 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
469 {
470 g_ventoy_debug_level = 1;
471 }
472
473 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
474 }
475
476 static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
477 {
478 (void)ctxt;
479
480 if (argc != 2)
481 {
482 return 1;
483 }
484
485 return (grub_strstr(args[0], args[1])) ? 0 : 1;
486 }
487
488 static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
489 {
490 char *c0, *c1;
491
492 (void)ctxt;
493
494 if (argc != 2)
495 {
496 return 1;
497 }
498
499 c0 = args[0];
500 c1 = args[1];
501
502 while (*c0 && *c1)
503 {
504 if (*c0 != *c1)
505 {
506 return 1;
507 }
508 c0++;
509 c1++;
510 }
511
512 if (*c1)
513 {
514 return 1;
515 }
516
517 return 0;
518 }
519
520 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
521 {
522 long value_long = 0;
523 char buf[32];
524
525 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
526 {
527 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
528 }
529
530 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
531 {
532 return grub_errno;
533 }
534
535 value_long += grub_strtol(args[1], NULL, 10);
536
537 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
538 grub_env_set(args[0], buf);
539
540 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
541 }
542
543 static grub_err_t ventoy_cmd_mod(grub_extcmd_context_t ctxt, int argc, char **args)
544 {
545 ulonglong value1 = 0;
546 ulonglong value2 = 0;
547 char buf[32];
548
549 if (argc != 3)
550 {
551 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name);
552 }
553
554 value1 = grub_strtoull(args[0], NULL, 10);
555 value2 = grub_strtoull(args[1], NULL, 10);
556
557 grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1)));
558 grub_env_set(args[2], buf);
559
560 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
561 }
562
563 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
564 {
565 int rc = 1;
566 char buf[32];
567 grub_file_t file;
568
569 (void)ctxt;
570 (void)argc;
571 (void)args;
572
573 if (argc != 2)
574 {
575 return rc;
576 }
577
578 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
579 if (file == NULL)
580 {
581 debug("failed to open file <%s> for udf check\n", args[0]);
582 return 1;
583 }
584
585 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
586
587 grub_env_set(args[1], buf);
588
589 grub_file_close(file);
590 rc = 0;
591
592 return rc;
593 }
594
595 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
596 {
597 grub_file_t file;
598
599 (void)ctxt;
600 (void)argc;
601 (void)args;
602
603 g_wimboot_enable = 0;
604 grub_check_free(g_wimiso_path);
605 grub_check_free(g_wimiso_chunk_list.chunk);
606
607 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
608 if (!file)
609 {
610 return 0;
611 }
612
613 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
614 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
615 if (NULL == g_wimiso_chunk_list.chunk)
616 {
617 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
618 }
619
620 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
621 g_wimiso_chunk_list.cur_chunk = 0;
622
623 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
624
625 g_wimboot_enable = 1;
626 g_wimiso_path = grub_strdup(args[0]);
627
628 grub_file_close(file);
629
630 return 0;
631 }
632
633 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
634 {
635 int len;
636 grub_file_t file;
637 char exec[128];
638 char *data = NULL;
639 grub_uint32_t offset;
640
641 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
642 if (file == NULL)
643 {
644 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
645 return 1;
646 }
647
648 len = (int)file->size;
649
650 data = (char *)grub_malloc(file->size);
651 if (!data)
652 {
653 return 1;
654 }
655
656 grub_file_read(file, data, file->size);
657 grub_file_close(file);
658
659 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
660 grub_script_execute_sourcecode(exec);
661
662 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
663 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
664 grub_file_close(file);
665
666 grub_script_execute_sourcecode("loopback -d efiboot");
667
668 *buf = data;
669 *datalen = len;
670 *direntoff = offset + 2;
671
672 return 0;
673 }
674
675 static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
676 {
677 int len = 0;
678 int totlen = 0;
679 int offset = 0;
680 grub_file_t file;
681 char name[32];
682 char value[32];
683 char *buf = NULL;
684 char *data = NULL;
685 ventoy_iso9660_override *dirent;
686
687 (void)ctxt;
688
689 if (argc != 2)
690 {
691 return 1;
692 }
693
694 totlen = sizeof(ventoy_chain_head);
695
696 if (ventoy_load_efiboot_template(&buf, &len, &offset))
697 {
698 debug("failed to load efiboot template %d\n", len);
699 return 1;
700 }
701
702 totlen += len;
703
704 debug("efiboot template len:%d offset:%d\n", len, offset);
705
706 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
707 if (file == NULL)
708 {
709 debug("failed to open file <%s>\n", args[0]);
710 return 1;
711 }
712
713 totlen += ventoy_align_2k(file->size);
714
715 dirent = (ventoy_iso9660_override *)(buf + offset);
716 dirent->first_sector = len / 2048;
717 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
718 dirent->size = (grub_uint32_t)file->size;
719 dirent->size_be = grub_swap_bytes32(dirent->size);
720
721 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
722
723 #ifdef GRUB_MACHINE_EFI
724 data = (char *)grub_efi_allocate_iso_buf(totlen);
725 #else
726 data = (char *)grub_malloc(totlen);
727 #endif
728
729 ventoy_fill_os_param(file, (ventoy_os_param *)data);
730
731 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
732 grub_check_free(buf);
733
734 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
735 grub_file_close(file);
736
737 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
738 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
739 grub_env_set(name, value);
740
741 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
742 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
743 grub_env_set(name, value);
744
745 return 0;
746 }
747
748 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
749 {
750 int rc = 1;
751 char name[32];
752 char value[32];
753 char *buf = NULL;
754 grub_file_t file;
755
756 (void)ctxt;
757 (void)argc;
758 (void)args;
759
760 if (argc != 2)
761 {
762 return rc;
763 }
764
765 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
766 if (file == NULL)
767 {
768 debug("failed to open file <%s>\n", args[0]);
769 return 1;
770 }
771
772 #ifdef GRUB_MACHINE_EFI
773 buf = (char *)grub_efi_allocate_iso_buf(file->size);
774 #else
775 buf = (char *)grub_malloc(file->size);
776 #endif
777
778 grub_file_read(file, buf, file->size);
779
780 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
781 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
782 grub_env_set(name, value);
783
784 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
785 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
786 grub_env_set(name, value);
787
788 grub_file_close(file);
789 rc = 0;
790
791 return rc;
792 }
793
794 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
795 {
796 int rc = 1;
797 int headlen;
798 char name[32];
799 char value[32];
800 char *buf = NULL;
801 grub_file_t file;
802
803 (void)ctxt;
804 (void)argc;
805 (void)args;
806
807 if (argc != 2)
808 {
809 return rc;
810 }
811
812 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
813 if (file == NULL)
814 {
815 debug("failed to open file <%s> for udf check\n", args[0]);
816 return 1;
817 }
818
819 headlen = sizeof(ventoy_chain_head);
820
821 #ifdef GRUB_MACHINE_EFI
822 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
823 #else
824 buf = (char *)grub_malloc(headlen + file->size);
825 #endif
826
827 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
828
829 grub_file_read(file, buf + headlen, file->size);
830
831 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
832 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
833 grub_env_set(name, value);
834
835 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
836 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
837 grub_env_set(name, value);
838
839 grub_file_close(file);
840 rc = 0;
841
842 return rc;
843 }
844
845 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
846 {
847 (void)ctxt;
848
849 if (argc != 1)
850 {
851 return 1;
852 }
853
854 if (args[0][0] == '1')
855 {
856 grub_iso9660_set_nojoliet(1);
857 }
858 else
859 {
860 grub_iso9660_set_nojoliet(0);
861 }
862
863 return 0;
864 }
865
866 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
867 {
868 int i;
869 int rc = 1;
870 grub_file_t file;
871 grub_uint8_t buf[32];
872
873 (void)ctxt;
874 (void)argc;
875 (void)args;
876
877 if (argc != 1)
878 {
879 return rc;
880 }
881
882 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
883 if (file == NULL)
884 {
885 debug("failed to open file <%s> for udf check\n", args[0]);
886 return 1;
887 }
888
889 for (i = 16; i < 32; i++)
890 {
891 grub_file_seek(file, i * 2048);
892 grub_file_read(file, buf, sizeof(buf));
893 if (buf[0] == 255)
894 {
895 break;
896 }
897 }
898
899 i++;
900 grub_file_seek(file, i * 2048);
901 grub_file_read(file, buf, sizeof(buf));
902
903 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
904 {
905 i++;
906 grub_file_seek(file, i * 2048);
907 grub_file_read(file, buf, sizeof(buf));
908
909 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
910 grub_memcmp(buf + 1, "NSR03", 5) == 0)
911 {
912 rc = 0;
913 }
914 }
915
916 grub_file_close(file);
917
918 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
919
920 return rc;
921 }
922
923 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
924 {
925 long value_long1 = 0;
926 long value_long2 = 0;
927
928 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
929 {
930 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
931 }
932
933 value_long1 = grub_strtol(args[0], NULL, 10);
934 value_long2 = grub_strtol(args[2], NULL, 10);
935
936 if (0 == grub_strcmp(args[1], "eq"))
937 {
938 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
939 }
940 else if (0 == grub_strcmp(args[1], "ne"))
941 {
942 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
943 }
944 else if (0 == grub_strcmp(args[1], "gt"))
945 {
946 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
947 }
948 else if (0 == grub_strcmp(args[1], "lt"))
949 {
950 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
951 }
952 else if (0 == grub_strcmp(args[1], "ge"))
953 {
954 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
955 }
956 else if (0 == grub_strcmp(args[1], "le"))
957 {
958 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
959 }
960 else
961 {
962 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
963 }
964
965 return grub_errno;
966 }
967
968 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
969 {
970 char *pos = NULL;
971 char buf[128] = {0};
972
973 if (argc != 2)
974 {
975 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
976 }
977
978 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
979 pos = grub_strstr(buf, ",");
980 if (pos)
981 {
982 *pos = 0;
983 }
984
985 grub_env_set(args[1], buf);
986
987 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
988 }
989
990 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
991 {
992 int i;
993 char buf[256];
994 grub_disk_t disk;
995 char *pos = NULL;
996 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
997
998 (void)ctxt;
999
1000 if (argc != 1)
1001 {
1002 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
1003 }
1004
1005 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
1006 {
1007 grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]);
1008 if (0 == grub_script_execute_sourcecode(buf))
1009 {
1010 debug("file %s exist, ventoy_compatible YES\n", buf);
1011 grub_env_set("ventoy_compatible", "YES");
1012 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1013 }
1014 else
1015 {
1016 debug("file %s NOT exist\n", buf);
1017 }
1018 }
1019
1020 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
1021 pos = grub_strstr(buf, ")");
1022 if (pos)
1023 {
1024 *pos = 0;
1025 }
1026
1027 disk = grub_disk_open(buf);
1028 if (disk)
1029 {
1030 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
1031 grub_disk_close(disk);
1032
1033 g_img_swap_tmp_buf[703] = 0;
1034 for (i = 318; i < 703; i++)
1035 {
1036 if (g_img_swap_tmp_buf[i] == 'V' &&
1037 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
1038 {
1039 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
1040 grub_env_set("ventoy_compatible", "YES");
1041 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1042 }
1043 }
1044 }
1045 else
1046 {
1047 debug("failed to open disk <%s>\n", buf);
1048 }
1049
1050 grub_env_set("ventoy_compatible", "NO");
1051 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1052 }
1053
1054 int ventoy_cmp_img(img_info *img1, img_info *img2)
1055 {
1056 char *s1, *s2;
1057 int c1 = 0;
1058 int c2 = 0;
1059
1060 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1061 {
1062 return (img1->plugin_list_index - img2->plugin_list_index);
1063 }
1064
1065 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1066 {
1067 c1 = *s1;
1068 c2 = *s2;
1069
1070 if (0 == g_sort_case_sensitive)
1071 {
1072 if (grub_islower(c1))
1073 {
1074 c1 = c1 - 'a' + 'A';
1075 }
1076
1077 if (grub_islower(c2))
1078 {
1079 c2 = c2 - 'a' + 'A';
1080 }
1081 }
1082
1083 if (c1 != c2)
1084 {
1085 break;
1086 }
1087 }
1088
1089 return (c1 - c2);
1090 }
1091
1092 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1093 {
1094 char *s1, *s2;
1095 int c1 = 0;
1096 int c2 = 0;
1097
1098 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1099 {
1100 return (node1->plugin_list_index - node2->plugin_list_index);
1101 }
1102
1103 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1104 {
1105 c1 = *s1;
1106 c2 = *s2;
1107
1108 if (0 == g_sort_case_sensitive)
1109 {
1110 if (grub_islower(c1))
1111 {
1112 c1 = c1 - 'a' + 'A';
1113 }
1114
1115 if (grub_islower(c2))
1116 {
1117 c2 = c2 - 'a' + 'A';
1118 }
1119 }
1120
1121 if (c1 != c2)
1122 {
1123 break;
1124 }
1125 }
1126
1127 return (c1 - c2);
1128 }
1129
1130 void ventoy_swap_img(img_info *img1, img_info *img2)
1131 {
1132 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1133
1134 grub_memcpy(img1, img2, sizeof(img_info));
1135 img1->next = g_img_swap_tmp.next;
1136 img1->prev = g_img_swap_tmp.prev;
1137
1138 g_img_swap_tmp.next = img2->next;
1139 g_img_swap_tmp.prev = img2->prev;
1140 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1141 }
1142
1143 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1144 {
1145 (void)namelen;
1146
1147 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1148 {
1149 return 0;
1150 }
1151
1152 return 1;
1153 }
1154
1155 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
1156 {
1157 if (0 == info->dir)
1158 {
1159 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
1160 {
1161 *((int *)data) = 1;
1162 return 0;
1163 }
1164 }
1165
1166 return 0;
1167 }
1168
1169 static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1170 {
1171 //int i = 0;
1172 int type = 0;
1173 int ignore = 0;
1174 int index = 0;
1175 grub_size_t len;
1176 img_info *img;
1177 img_info *tail;
1178 img_iterator_node *tmp;
1179 img_iterator_node *new_node;
1180 img_iterator_node *node = (img_iterator_node *)data;
1181
1182 if (g_enumerate_time_checked == 0)
1183 {
1184 g_enumerate_finish_time_ms = grub_get_time_ms();
1185 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1186 {
1187 grub_cls();
1188 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1189 grub_refresh();
1190 g_enumerate_time_checked = 1;
1191 }
1192 }
1193
1194 len = grub_strlen(filename);
1195
1196 if (info->dir)
1197 {
1198 if (node->level + 1 > g_img_max_search_level)
1199 {
1200 return 0;
1201 }
1202
1203 if ((len == 1 && filename[0] == '.') ||
1204 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1205 {
1206 return 0;
1207 }
1208
1209 if (!ventoy_img_name_valid(filename, len))
1210 {
1211 return 0;
1212 }
1213
1214 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1215 {
1216 return 0;
1217 }
1218
1219 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1220 {
1221 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1222 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1223 if (index == 0)
1224 {
1225 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1226 return 0;
1227 }
1228 }
1229
1230 new_node = grub_zalloc(sizeof(img_iterator_node));
1231 if (new_node)
1232 {
1233 new_node->level = node->level + 1;
1234 new_node->plugin_list_index = index;
1235 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1236
1237 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1238 if (ignore)
1239 {
1240 debug("Directory %s ignored...\n", new_node->dir);
1241 grub_free(new_node);
1242 return 0;
1243 }
1244
1245 new_node->tail = node->tail;
1246
1247 new_node->parent = node;
1248 if (!node->firstchild)
1249 {
1250 node->firstchild = new_node;
1251 }
1252
1253 if (g_img_iterator_tail)
1254 {
1255 g_img_iterator_tail->next = new_node;
1256 g_img_iterator_tail = new_node;
1257 }
1258 else
1259 {
1260 g_img_iterator_head.next = new_node;
1261 g_img_iterator_tail = new_node;
1262 }
1263 }
1264 }
1265 else
1266 {
1267 debug("Find a file %s\n", filename);
1268 if (len < 4)
1269 {
1270 return 0;
1271 }
1272
1273 if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
1274 {
1275 type = img_type_iso;
1276 }
1277 else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1278 {
1279 type = img_type_wim;
1280 }
1281 else if (g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1282 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1283 {
1284 type = img_type_vhd;
1285 }
1286 #ifdef GRUB_MACHINE_EFI
1287 else if (0 == grub_strcasecmp(filename + len - 4, ".efi"))
1288 {
1289 type = img_type_efi;
1290 }
1291 #endif
1292 else if (0 == grub_strcasecmp(filename + len - 4, ".img"))
1293 {
1294 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1295 {
1296 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1297 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1298 {
1299 return 0;
1300 }
1301 }
1302 type = img_type_img;
1303 }
1304 else if (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1305 {
1306 type = img_type_vtoy;
1307 }
1308 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1309 {
1310 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1311 {
1312 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1313 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1314 }
1315 return 0;
1316 }
1317 else
1318 {
1319 return 0;
1320 }
1321
1322 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1323 {
1324 return 0;
1325 }
1326
1327 if (g_plugin_image_list)
1328 {
1329 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1330 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1331 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1332 {
1333 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1334 return 0;
1335 }
1336 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
1337 {
1338 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf);
1339 return 0;
1340 }
1341 }
1342
1343 img = grub_zalloc(sizeof(img_info));
1344 if (img)
1345 {
1346 img->type = type;
1347 img->plugin_list_index = index;
1348 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1349
1350 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1351
1352 img->size = info->size;
1353 if (0 == img->size)
1354 {
1355 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1356 }
1357
1358 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1359 {
1360 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1361 grub_free(img);
1362 return 0;
1363 }
1364
1365 if (g_ventoy_img_list)
1366 {
1367 tail = *(node->tail);
1368 img->prev = tail;
1369 tail->next = img;
1370 }
1371 else
1372 {
1373 g_ventoy_img_list = img;
1374 }
1375
1376 img->id = g_ventoy_img_count;
1377 img->parent = node;
1378 if (node && NULL == node->firstiso)
1379 {
1380 node->firstiso = img;
1381 }
1382
1383 node->isocnt++;
1384 tmp = node->parent;
1385 while (tmp)
1386 {
1387 tmp->isocnt++;
1388 tmp = tmp->parent;
1389 }
1390
1391 *((img_info **)(node->tail)) = img;
1392 g_ventoy_img_count++;
1393
1394 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1395 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1396 if (!img->class)
1397 {
1398 img->class = g_menu_class[type];
1399 }
1400 img->menu_prefix = g_menu_prefix[type];
1401
1402 if (img_type_iso == type)
1403 {
1404 if (ventoy_plugin_check_memdisk(img->path))
1405 {
1406 img->menu_prefix = "miso";
1407 }
1408 }
1409
1410 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1411 }
1412 }
1413
1414 return 0;
1415 }
1416
1417 static int ventoy_arch_mode_init(void)
1418 {
1419 #ifdef GRUB_MACHINE_EFI
1420 if (grub_strcmp(GRUB_TARGET_CPU, "i386") == 0)
1421 {
1422 g_ventoy_plat_data = VTOY_PLAT_I386_UEFI;
1423 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "ia32");
1424 }
1425 else if (grub_strcmp(GRUB_TARGET_CPU, "arm64") == 0)
1426 {
1427 g_ventoy_plat_data = VTOY_PLAT_ARM64_UEFI;
1428 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "aa64");
1429 }
1430 else if (grub_strcmp(GRUB_TARGET_CPU, "mips64el") == 0)
1431 {
1432 g_ventoy_plat_data = VTOY_PLAT_MIPS_UEFI;
1433 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "mips");
1434 }
1435 else
1436 {
1437 g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI;
1438 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi");
1439 }
1440 #else
1441 g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY;
1442 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy");
1443 #endif
1444
1445 return 0;
1446 }
1447
1448 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1449 {
1450 int len = GRUB_UINT_MAX;
1451 const char *value = NULL;
1452 char name[32] = {0};
1453 char plat[32] = {0};
1454 char guidstr[32] = {0};
1455 ventoy_guid guid = VENTOY_GUID;
1456 const char *fmt1 = NULL;
1457 const char *fmt2 = NULL;
1458 const char *fmt3 = NULL;
1459 grub_uint32_t *puint = (grub_uint32_t *)name;
1460 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1461 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1462 const char fmtcode[]={
1463 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1464 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1465 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1466 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1467 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1468 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1469 };
1470
1471 grub_memset(name, 0, sizeof(name));
1472 puint[0] = grub_swap_bytes32(0x56454e54);
1473 puint[3] = grub_swap_bytes32(0x4f4e0000);
1474 puint[2] = grub_swap_bytes32(0x45525349);
1475 puint[1] = grub_swap_bytes32(0x4f595f56);
1476 value = ventoy_get_env(name);
1477
1478 grub_memset(name, 0, sizeof(name));
1479 puint[1] = grub_swap_bytes32(0x5f544f50);
1480 puint[0] = grub_swap_bytes32(0x56544c45);
1481 fmt1 = ventoy_get_env(name);
1482 if (!fmt1)
1483 {
1484 fmt1 = fmtdata;
1485 }
1486
1487 grub_memset(name, 0, sizeof(name));
1488 puint[1] = grub_swap_bytes32(0x5f4c4654);
1489 puint[0] = grub_swap_bytes32(0x56544c45);
1490 fmt2 = ventoy_get_env(name);
1491
1492 grub_memset(name, 0, sizeof(name));
1493 puint[1] = grub_swap_bytes32(0x5f434c52);
1494 puint[0] = grub_swap_bytes32(0x56544c45);
1495 fmt3 = ventoy_get_env(name);
1496
1497 grub_memcpy(guidstr, &guid, sizeof(guid));
1498
1499 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1500
1501 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1502 #pragma GCC diagnostic push
1503 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1504 len = grub_snprintf(buffer, buflen, fmtcode,
1505 fmt1 ? fmt1 : fmtdata,
1506 fmt2 ? fmt2 : fmtdata + 4,
1507 value ? value : "", plat, guidstr,
1508 fmt3 ? fmt3 : fmtdata + 6);
1509 #pragma GCC diagnostic pop
1510
1511 grub_memset(name, 0, sizeof(name));
1512 puint[0] = grub_swap_bytes32(0x76746f79);
1513 puint[2] = grub_swap_bytes32(0x656e7365);
1514 puint[1] = grub_swap_bytes32(0x5f6c6963);
1515 ventoy_set_env(name, guidstr);
1516
1517 return len;
1518 }
1519
1520 int ventoy_check_password(const vtoy_password *pwd, int retry)
1521 {
1522 int offset;
1523 char input[256];
1524 grub_uint8_t md5[16];
1525
1526 while (retry--)
1527 {
1528 grub_memset(input, 0, sizeof(input));
1529
1530 grub_printf("Enter password: ");
1531 grub_refresh();
1532
1533 if (pwd->type == VTOY_PASSWORD_TXT)
1534 {
1535 grub_password_get(input, 128);
1536 if (grub_strcmp(pwd->text, input) == 0)
1537 {
1538 return 0;
1539 }
1540 }
1541 else if (pwd->type == VTOY_PASSWORD_MD5)
1542 {
1543 grub_password_get(input, 128);
1544 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1545 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1546 {
1547 return 0;
1548 }
1549 }
1550 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1551 {
1552 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1553 grub_password_get(input + offset, 128);
1554
1555 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1556 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1557 {
1558 return 0;
1559 }
1560 }
1561
1562 grub_printf("Invalid password!\n\n");
1563 grub_refresh();
1564 }
1565
1566 return 1;
1567 }
1568
1569 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1570 {
1571 img_info *minimg = NULL;
1572 img_info *img = (img_info *)(node->firstiso);
1573
1574 while (img && (img_iterator_node *)(img->parent) == node)
1575 {
1576 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1577 {
1578 minimg = img;
1579 }
1580 img = img->next;
1581 }
1582
1583 if (minimg)
1584 {
1585 minimg->select = 1;
1586 }
1587
1588 return minimg;
1589 }
1590
1591 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1592 {
1593 img_iterator_node *Minchild = NULL;
1594 img_iterator_node *child = node->firstchild;
1595
1596 while (child && child->parent == node)
1597 {
1598 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1599 {
1600 Minchild = child;
1601 }
1602 child = child->next;
1603 }
1604
1605 if (Minchild)
1606 {
1607 Minchild->select = 1;
1608 }
1609
1610 return Minchild;
1611 }
1612
1613 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1614 {
1615 int offset = 1;
1616 img_info *img = NULL;
1617 const char *dir_class = NULL;
1618 const char *dir_alias = NULL;
1619 img_iterator_node *child = NULL;
1620
1621 if (node->isocnt == 0 || node->done == 1)
1622 {
1623 return 0;
1624 }
1625
1626 if (node->parent && node->parent->dirlen < node->dirlen)
1627 {
1628 offset = node->parent->dirlen;
1629 }
1630
1631 if (node == &g_img_iterator_head)
1632 {
1633 if (g_default_menu_mode == 0)
1634 {
1635 if (g_tree_view_menu_style == 0)
1636 {
1637 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1638 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1639 " echo 'return ...' \n"
1640 "}\n", "<--");
1641 }
1642 else
1643 {
1644 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1645 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1646 " echo '%s ...' \n"
1647 "}\n", "return");
1648 }
1649 }
1650 }
1651 else
1652 {
1653 node->dir[node->dirlen - 1] = 0;
1654 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1655 if (!dir_class)
1656 {
1657 dir_class = "vtoydir";
1658 }
1659
1660 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1661 if (dir_alias)
1662 {
1663 if (g_tree_view_menu_style == 0)
1664 {
1665 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1666 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1667 "DIR", dir_alias, dir_class, node->dir + offset);
1668 }
1669 else
1670 {
1671 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1672 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1673 dir_alias, dir_class, node->dir + offset);
1674 }
1675 }
1676 else
1677 {
1678 dir_alias = node->dir + offset;
1679
1680 if (g_tree_view_menu_style == 0)
1681 {
1682 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1683 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1684 "DIR", dir_alias, dir_class, node->dir + offset);
1685 }
1686 else
1687 {
1688 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1689 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1690 dir_alias, dir_class, node->dir + offset);
1691 }
1692 }
1693
1694 if (g_tree_view_menu_style == 0)
1695 {
1696 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1697 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1698 " echo 'return ...' \n"
1699 "}\n", "<--");
1700 }
1701 else
1702 {
1703 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1704 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1705 " echo '%s ...' \n"
1706 "}\n", "return");
1707 }
1708 }
1709
1710 while ((child = ventoy_get_min_child(node)) != NULL)
1711 {
1712 ventoy_dynamic_tree_menu(child);
1713 }
1714
1715 while ((img = ventoy_get_min_iso(node)) != NULL)
1716 {
1717 if (g_tree_view_menu_style == 0)
1718 {
1719 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1720 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1721 " %s_%s \n"
1722 "}\n",
1723 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1724 img->unsupport ? "[***********] " : "",
1725 img->alias ? img->alias : img->name, img->class, img->id,
1726 img->menu_prefix,
1727 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1728 }
1729 else
1730 {
1731 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1732 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1733 " %s_%s \n"
1734 "}\n",
1735 img->unsupport ? "[***********] " : "",
1736 img->alias ? img->alias : img->name, img->class, img->id,
1737 img->menu_prefix,
1738 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1739 }
1740 }
1741
1742 if (node != &g_img_iterator_head)
1743 {
1744 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1745 }
1746
1747 node->done = 1;
1748 return 0;
1749 }
1750
1751 int ventoy_check_device_result(int ret)
1752 {
1753 char buf[32];
1754
1755 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1756 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1757 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1758
1759 if (ret)
1760 {
1761 grub_printf(VTOY_WARNING"\n");
1762 grub_printf(VTOY_WARNING"\n");
1763 grub_printf(VTOY_WARNING"\n\n\n");
1764
1765 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1766 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1767
1768 grub_printf("\n\nWill exit after 10 seconds ...... ");
1769 grub_refresh();
1770 grub_sleep(10);
1771 }
1772
1773 return ret;
1774 }
1775
1776 int ventoy_check_device(grub_device_t dev)
1777 {
1778 int workaround = 0;
1779 grub_file_t file;
1780 grub_uint64_t offset;
1781 char devname[64];
1782 grub_fs_t fs;
1783 grub_device_t dev2;
1784 char *label = NULL;
1785 struct grub_partition *partition;
1786
1787 if (dev->disk == NULL || dev->disk->partition == NULL)
1788 {
1789 return ventoy_check_device_result(1 | 0x1000);
1790 }
1791
1792 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1793 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1794 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1795 {
1796 #ifndef GRUB_MACHINE_EFI
1797 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
1798 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
1799 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1800 {
1801 return ventoy_check_device_result(2 | 0x1000);
1802 }
1803 else
1804 {
1805 workaround = 1;
1806 }
1807 #endif
1808 }
1809
1810 /* We must have partition 2 */
1811 if (workaround)
1812 {
1813 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1814 }
1815 else
1816 {
1817 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1818 }
1819 if (!file)
1820 {
1821 return ventoy_check_device_result(3 | 0x1000);
1822 }
1823
1824 if (NULL == grub_strstr(file->fs->name, "fat"))
1825 {
1826 grub_file_close(file);
1827 return ventoy_check_device_result(4 | 0x1000);
1828 }
1829
1830 partition = dev->disk->partition;
1831 if (partition->number != 0 || partition->start != 2048)
1832 {
1833 return ventoy_check_device_result(5);
1834 }
1835
1836 if (workaround)
1837 {
1838 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
1839 {
1840 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
1841 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
1842 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
1843 {
1844 grub_file_close(file);
1845 return ventoy_check_device_result(6);
1846 }
1847 }
1848 else
1849 {
1850 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
1851 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
1852 PartTbl[1].SectorCount != 65536)
1853 {
1854 grub_file_close(file);
1855 return ventoy_check_device_result(6);
1856 }
1857 }
1858 }
1859 else
1860 {
1861 offset = partition->start + partition->len;
1862 partition = file->device->disk->partition;
1863 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1864 {
1865 grub_file_close(file);
1866 return ventoy_check_device_result(7);
1867 }
1868 }
1869
1870 grub_file_close(file);
1871
1872 if (workaround == 0)
1873 {
1874 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1875 dev2 = grub_device_open(devname);
1876 if (!dev2)
1877 {
1878 return ventoy_check_device_result(8);
1879 }
1880
1881 fs = grub_fs_probe(dev2);
1882 if (!fs)
1883 {
1884 grub_device_close(dev2);
1885 return ventoy_check_device_result(9);
1886 }
1887
1888 fs->fs_label(dev2, &label);
1889 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1890 {
1891 grub_device_close(dev2);
1892 return ventoy_check_device_result(10);
1893 }
1894
1895 grub_device_close(dev2);
1896 }
1897
1898 return ventoy_check_device_result(0);
1899 }
1900
1901 static int ventoy_set_default_menu(void)
1902 {
1903 int img_len = 0;
1904 char *pos = NULL;
1905 char *end = NULL;
1906 char *def = NULL;
1907 const char *strdata = NULL;
1908 img_info *cur = NULL;
1909 img_info *default_node = NULL;
1910 const char *default_image = NULL;
1911
1912 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1913 if (default_image && default_image[0] == '/')
1914 {
1915 img_len = grub_strlen(default_image);
1916
1917 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1918 {
1919 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1920 {
1921 default_node = cur;
1922 break;
1923 }
1924 }
1925
1926 if (!default_node)
1927 {
1928 return 1;
1929 }
1930
1931 if (0 == g_default_menu_mode)
1932 {
1933 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1934 }
1935 else
1936 {
1937 def = grub_strdup(default_image);
1938 if (!def)
1939 {
1940 return 1;
1941 }
1942
1943 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1944
1945 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1946 if (strdata && strdata[0] == '/')
1947 {
1948 pos = def + grub_strlen(strdata);
1949 if (*pos == '/')
1950 {
1951 pos++;
1952 }
1953 }
1954 else
1955 {
1956 pos = def + 1;
1957 }
1958
1959 while ((end = grub_strchr(pos, '/')) != NULL)
1960 {
1961 *end = 0;
1962 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1963 pos = end + 1;
1964 }
1965
1966 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1967 grub_free(def);
1968 }
1969 }
1970
1971 return 0;
1972 }
1973
1974 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1975 {
1976 int len;
1977 grub_fs_t fs;
1978 grub_device_t dev = NULL;
1979 img_info *cur = NULL;
1980 img_info *tail = NULL;
1981 const char *strdata = NULL;
1982 char *device_name = NULL;
1983 char buf[32];
1984 img_iterator_node *node = NULL;
1985 img_iterator_node *tmp = NULL;
1986
1987 (void)ctxt;
1988
1989 if (argc != 2)
1990 {
1991 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1992 }
1993
1994 if (g_ventoy_img_list || g_ventoy_img_count)
1995 {
1996 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1997 }
1998
1999 g_enumerate_time_checked = 0;
2000 g_enumerate_start_time_ms = grub_get_time_ms();
2001
2002 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2003 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2004 {
2005 g_filt_dot_underscore_file = 1;
2006 }
2007
2008 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2009 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2010 {
2011 g_sort_case_sensitive = 1;
2012 }
2013
2014 device_name = grub_file_get_device_name(args[0]);
2015 if (!device_name)
2016 {
2017 goto fail;
2018 }
2019
2020 g_enum_dev = dev = grub_device_open(device_name);
2021 if (!dev)
2022 {
2023 goto fail;
2024 }
2025
2026 g_enum_fs = fs = grub_fs_probe(dev);
2027 if (!fs)
2028 {
2029 goto fail;
2030 }
2031
2032 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2033 {
2034 debug("unsupported fs:<%s>\n", fs->name);
2035 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2036 goto fail;
2037 }
2038
2039 ventoy_set_env("vtoy_iso_fs", fs->name);
2040
2041 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2042 if (strdata && strdata[0] == '1')
2043 {
2044 g_default_menu_mode = 1;
2045 }
2046
2047 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2048
2049 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2050
2051 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2052 if (strdata && strdata[0] == '/')
2053 {
2054 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2055 if (g_img_iterator_head.dir[len - 1] != '/')
2056 {
2057 g_img_iterator_head.dir[len++] = '/';
2058 }
2059 g_img_iterator_head.dirlen = len;
2060 }
2061 else
2062 {
2063 g_img_iterator_head.dirlen = 1;
2064 grub_strcpy(g_img_iterator_head.dir, "/");
2065 }
2066
2067 g_img_iterator_head.tail = &tail;
2068
2069 if (g_img_max_search_level < 0)
2070 {
2071 g_img_max_search_level = GRUB_INT_MAX;
2072 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2073 if (strdata && ventoy_is_decimal(strdata))
2074 {
2075 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2076 }
2077 }
2078
2079 for (node = &g_img_iterator_head; node; node = node->next)
2080 {
2081 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2082 }
2083
2084 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2085 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2086 {
2087 g_tree_view_menu_style = 1;
2088 }
2089
2090 ventoy_set_default_menu();
2091
2092 for (node = &g_img_iterator_head; node; node = node->next)
2093 {
2094 ventoy_dynamic_tree_menu(node);
2095 }
2096
2097 /* free node */
2098 node = g_img_iterator_head.next;
2099 while (node)
2100 {
2101 tmp = node->next;
2102 grub_free(node);
2103 node = tmp;
2104 }
2105
2106 /* sort image list by image name */
2107 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2108 {
2109 for (tail = cur->next; tail; tail = tail->next)
2110 {
2111 if (ventoy_cmp_img(cur, tail) > 0)
2112 {
2113 ventoy_swap_img(cur, tail);
2114 }
2115 }
2116 }
2117
2118 if (g_default_menu_mode == 1)
2119 {
2120 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2121 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2122 " echo 'return ...' \n"
2123 "}\n", "<--");
2124 }
2125
2126 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2127 {
2128 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2129 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2130 " %s_%s \n"
2131 "}\n",
2132 cur->unsupport ? "[***********] " : "",
2133 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2134 cur->menu_prefix,
2135 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2136 }
2137
2138 g_tree_script_buf[g_tree_script_pos] = 0;
2139 g_list_script_buf[g_list_script_pos] = 0;
2140
2141 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2142 grub_env_set(args[1], buf);
2143
2144 fail:
2145
2146 check_free(device_name, grub_free);
2147 check_free(dev, grub_device_close);
2148
2149 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2150 }
2151
2152
2153 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2154 {
2155 img_info *next = NULL;
2156 img_info *cur = g_ventoy_img_list;
2157
2158 (void)ctxt;
2159 (void)argc;
2160 (void)args;
2161
2162 while (cur)
2163 {
2164 next = cur->next;
2165 grub_free(cur);
2166 cur = next;
2167 }
2168
2169 g_ventoy_img_list = NULL;
2170 g_ventoy_img_count = 0;
2171
2172 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2173 }
2174
2175 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2176 {
2177 long img_id = 0;
2178 img_info *cur = g_ventoy_img_list;
2179
2180 (void)ctxt;
2181
2182 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2183 {
2184 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2185 }
2186
2187 img_id = grub_strtol(args[0], NULL, 10);
2188 if (img_id >= g_ventoy_img_count)
2189 {
2190 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2191 }
2192
2193 debug("Find image %ld name \n", img_id);
2194
2195 while (cur && img_id > 0)
2196 {
2197 img_id--;
2198 cur = cur->next;
2199 }
2200
2201 if (!cur)
2202 {
2203 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2204 }
2205
2206 debug("image name is %s\n", cur->name);
2207
2208 grub_env_set(args[1], cur->name);
2209
2210 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2211 }
2212
2213 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2214 {
2215 int img_id = 0;
2216 char value[32];
2217 char *pos = NULL;
2218 const char *id = NULL;
2219 img_info *cur = g_ventoy_img_list;
2220
2221 (void)ctxt;
2222
2223 if (argc < 1 || argc > 2)
2224 {
2225 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2226 }
2227
2228 id = grub_env_get("chosen");
2229
2230 pos = grub_strstr(id, "VID_");
2231 if (pos)
2232 {
2233 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2234 }
2235 else
2236 {
2237 img_id = (int)grub_strtoul(id, NULL, 10);
2238 }
2239
2240 while (cur)
2241 {
2242 if (img_id == cur->id)
2243 {
2244 break;
2245 }
2246 cur = cur->next;
2247 }
2248
2249 if (!cur)
2250 {
2251 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2252 }
2253
2254 grub_env_set(args[0], cur->path);
2255
2256 if (argc > 1)
2257 {
2258 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2259 grub_env_set(args[1], value);
2260 }
2261
2262 g_svd_replace_offset = 0;
2263
2264 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2265 }
2266
2267 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2268 {
2269 grub_disk_t disk;
2270 char *device_name;
2271 char *pos;
2272 char *pos2;
2273
2274 device_name = grub_file_get_device_name(filename);
2275 if (!device_name)
2276 {
2277 return 1;
2278 }
2279
2280 pos = device_name;
2281 if (pos[0] == '(')
2282 {
2283 pos++;
2284 }
2285
2286 pos2 = grub_strstr(pos, ",");
2287 if (!pos2)
2288 {
2289 pos2 = grub_strstr(pos, ")");
2290 }
2291
2292 if (pos2)
2293 {
2294 *pos2 = 0;
2295 }
2296
2297 disk = grub_disk_open(pos);
2298 if (disk)
2299 {
2300 grub_disk_read(disk, 0, 0x180, 16, guid);
2301 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2302 grub_disk_close(disk);
2303 }
2304 else
2305 {
2306 return 1;
2307 }
2308
2309 grub_free(device_name);
2310 return 0;
2311 }
2312
2313 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2314 {
2315 eltorito_descriptor desc;
2316
2317 grub_memset(&desc, 0, sizeof(desc));
2318 grub_file_seek(file, 17 * 2048);
2319 grub_file_read(file, &desc, sizeof(desc));
2320
2321 if (desc.type != 0 || desc.version != 1)
2322 {
2323 return 0;
2324 }
2325
2326 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2327 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2328 {
2329 return 0;
2330 }
2331
2332 return desc.sector;
2333 }
2334
2335 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2336 {
2337 int i;
2338 int x86count = 0;
2339 grub_uint8_t buf[512];
2340 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2341
2342 grub_file_seek(file, sector * 2048);
2343 grub_file_read(file, buf, sizeof(buf));
2344
2345 if (buf[0] == 0x01 && buf[1] == 0xEF)
2346 {
2347 debug("%s efi eltorito in Validation Entry\n", file->name);
2348 return 1;
2349 }
2350
2351 if (buf[0] == 0x01 && buf[1] == 0x00)
2352 {
2353 x86count++;
2354 }
2355
2356 for (i = 64; i < (int)sizeof(buf); i += 32)
2357 {
2358 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2359 {
2360 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2361 return 1;
2362 }
2363
2364 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2365 {
2366 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2367 return 1;
2368 }
2369 }
2370
2371 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2372 {
2373 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2374 {
2375 if (buf[36] == parttype[i])
2376 {
2377 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2378 return 1;
2379 }
2380 }
2381 }
2382
2383 debug("%s does not contain efi eltorito\n", file->name);
2384 return 0;
2385 }
2386
2387 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2388 {
2389 char *pos;
2390 const char *fs = NULL;
2391 const char *cdprompt = NULL;
2392 grub_uint32_t i;
2393 grub_uint8_t chksum = 0;
2394 grub_disk_t disk;
2395
2396 disk = file->device->disk;
2397 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2398
2399 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2400 param->vtoy_disk_part_id = disk->partition->number + 1;
2401 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2402
2403 pos = grub_strstr(file->name, "/");
2404 if (!pos)
2405 {
2406 pos = file->name;
2407 }
2408
2409 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2410
2411 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2412
2413 param->vtoy_img_size = file->size;
2414
2415 param->vtoy_reserved[0] = g_ventoy_break_level;
2416 param->vtoy_reserved[1] = g_ventoy_debug_level;
2417
2418 param->vtoy_reserved[2] = g_ventoy_chain_type;
2419
2420 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2421 param->vtoy_reserved[4] = 0;
2422 if (g_ventoy_chain_type == 1) /* Windows */
2423 {
2424 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2425 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2426 {
2427 param->vtoy_reserved[4] = 1;
2428 }
2429 }
2430
2431 fs = ventoy_get_env("ventoy_fs_probe");
2432 if (fs && grub_strcmp(fs, "udf") == 0)
2433 {
2434 param->vtoy_reserved[3] = 1;
2435 }
2436
2437 /* calculate checksum */
2438 for (i = 0; i < sizeof(ventoy_os_param); i++)
2439 {
2440 chksum += *((grub_uint8_t *)param + i);
2441 }
2442 param->chksum = (grub_uint8_t)(0x100 - chksum);
2443
2444 return;
2445 }
2446
2447 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2448 {
2449 grub_uint32_t i = 0;
2450 grub_uint64_t total = 0;
2451 ventoy_img_chunk *chunk = NULL;
2452
2453 for (i = 0; i < chunklist->cur_chunk; i++)
2454 {
2455 chunk = chunklist->chunk + i;
2456
2457 if (chunk->disk_start_sector <= start)
2458 {
2459 debug("%u disk start invalid %lu\n", i, (ulong)start);
2460 return 1;
2461 }
2462
2463 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2464 }
2465
2466 if (total != ((file->size + 511) / 512))
2467 {
2468 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2469 return 1;
2470 }
2471
2472 return 0;
2473 }
2474
2475 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2476 {
2477 int fs_type;
2478 int len;
2479 grub_uint32_t i = 0;
2480 grub_uint32_t sector = 0;
2481 grub_uint32_t count = 0;
2482 grub_off_t size = 0;
2483 grub_off_t read = 0;
2484
2485 fs_type = ventoy_get_fs_type(file->fs->name);
2486 if (fs_type == ventoy_fs_exfat)
2487 {
2488 grub_fat_get_file_chunk(start, file, chunklist);
2489 }
2490 else if (fs_type == ventoy_fs_ext)
2491 {
2492 grub_ext_get_file_chunk(start, file, chunklist);
2493 }
2494 else
2495 {
2496 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2497 file->read_hook_data = chunklist;
2498
2499 for (size = file->size; size > 0; size -= read)
2500 {
2501 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2502 grub_file_read(file, NULL, read);
2503 }
2504
2505 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2506 {
2507 chunklist->chunk[i].disk_start_sector += start;
2508 chunklist->chunk[i].disk_end_sector += start;
2509 }
2510
2511 if (ventoy_fs_udf == fs_type)
2512 {
2513 for (i = 0; i < chunklist->cur_chunk; i++)
2514 {
2515 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2516 chunklist->chunk[i].img_start_sector = sector;
2517 chunklist->chunk[i].img_end_sector = sector + count - 1;
2518 sector += count;
2519 }
2520 }
2521 }
2522
2523 len = (int)grub_strlen(file->name);
2524 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2525 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2526 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2527 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2528 {
2529 for (i = 0; i < chunklist->cur_chunk; i++)
2530 {
2531 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2532 if (count < 4)
2533 {
2534 count = 1;
2535 }
2536 else
2537 {
2538 count >>= 2;
2539 }
2540
2541 chunklist->chunk[i].img_start_sector = sector;
2542 chunklist->chunk[i].img_end_sector = sector + count - 1;
2543 sector += count;
2544 }
2545 }
2546
2547 return 0;
2548 }
2549
2550 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2551 {
2552 int rc;
2553 grub_file_t file;
2554 grub_disk_addr_t start;
2555
2556 (void)ctxt;
2557 (void)argc;
2558
2559 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2560 if (!file)
2561 {
2562 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2563 }
2564
2565 g_conf_replace_node = NULL;
2566 g_conf_replace_offset = 0;
2567
2568 if (g_img_chunk_list.chunk)
2569 {
2570 grub_free(g_img_chunk_list.chunk);
2571 }
2572
2573 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2574 {
2575 grub_file_close(file);
2576 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2577 }
2578
2579 /* get image chunk data */
2580 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2581 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2582 if (NULL == g_img_chunk_list.chunk)
2583 {
2584 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2585 }
2586
2587 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2588 g_img_chunk_list.cur_chunk = 0;
2589
2590 start = file->device->disk->partition->start;
2591
2592 ventoy_get_block_list(file, &g_img_chunk_list, start);
2593
2594 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2595 grub_file_close(file);
2596
2597 if (rc)
2598 {
2599 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2600 }
2601
2602 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2603 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2604 }
2605
2606 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2607 {
2608 grub_uint64_t offset = 0;
2609 grub_uint32_t align = 0;
2610 grub_file_t file = NULL;
2611 conf_replace *node = NULL;
2612
2613 (void)ctxt;
2614 (void)argc;
2615 (void)args;
2616
2617 debug("select conf replace argc:%d\n", argc);
2618
2619 if (argc < 2)
2620 {
2621 return 0;
2622 }
2623
2624 node = ventoy_plugin_find_conf_replace(args[1]);
2625 if (!node)
2626 {
2627 debug("Conf replace not found for %s\n", args[1]);
2628 goto end;
2629 }
2630
2631 debug("Find conf replace for %s\n", args[1]);
2632
2633 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2634 if (!file)
2635 {
2636 debug("<(loop)%s> NOT exist\n", node->orgconf);
2637 goto end;
2638 }
2639
2640 offset = grub_iso9660_get_last_file_dirent_pos(file);
2641 grub_file_close(file);
2642
2643 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2644 if (!file)
2645 {
2646 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2647 goto end;
2648 }
2649
2650 align = ((int)file->size + 2047) / 2048 * 2048;
2651
2652 if (align > vtoy_max_replace_file_size)
2653 {
2654 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2655 goto end;
2656 }
2657
2658 grub_file_read(file, g_conf_replace_new_buf, file->size);
2659 g_conf_replace_new_len = (int)file->size;
2660 g_conf_replace_new_len_align = align;
2661
2662 g_conf_replace_node = node;
2663 g_conf_replace_offset = offset + 2;
2664
2665 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2666
2667 end:
2668 if (file)
2669 {
2670 grub_file_close(file);
2671 }
2672 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2673 }
2674
2675 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2676 {
2677 int i = 0;
2678 int pos = 0;
2679 char *buf = NULL;
2680 char configfile[128];
2681 install_template *node = NULL;
2682
2683 (void)ctxt;
2684 (void)argc;
2685 (void)args;
2686
2687 debug("select auto installation argc:%d\n", argc);
2688
2689 if (argc < 1)
2690 {
2691 return 0;
2692 }
2693
2694 node = ventoy_plugin_find_install_template(args[0]);
2695 if (!node)
2696 {
2697 debug("Auto install template not found for %s\n", args[0]);
2698 return 0;
2699 }
2700
2701 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2702 {
2703 node->cursel = node->autosel - 1;
2704 debug("Auto install template auto select %d\n", node->autosel);
2705 return 0;
2706 }
2707
2708 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2709 if (!buf)
2710 {
2711 return 0;
2712 }
2713
2714 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2715 " echo %s\n}\n", "123");
2716
2717 for (i = 0; i < node->templatenum; i++)
2718 {
2719 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2720 " echo 123\n}\n",
2721 node->templatepath[i].path);
2722 }
2723
2724 g_ventoy_menu_esc = 1;
2725 g_ventoy_suppress_esc = 1;
2726
2727 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2728 grub_script_execute_sourcecode(configfile);
2729
2730 g_ventoy_menu_esc = 0;
2731 g_ventoy_suppress_esc = 0;
2732
2733 grub_free(buf);
2734
2735 node->cursel = g_ventoy_last_entry - 1;
2736
2737 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2738 }
2739
2740 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2741 {
2742 int i = 0;
2743 int pos = 0;
2744 char *buf = NULL;
2745 char configfile[128];
2746 persistence_config *node;
2747
2748 (void)ctxt;
2749 (void)argc;
2750 (void)args;
2751
2752 debug("select persistence argc:%d\n", argc);
2753
2754 if (argc < 1)
2755 {
2756 return 0;
2757 }
2758
2759 node = ventoy_plugin_find_persistent(args[0]);
2760 if (!node)
2761 {
2762 debug("Persistence image not found for %s\n", args[0]);
2763 return 0;
2764 }
2765
2766 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2767 {
2768 node->cursel = node->autosel - 1;
2769 debug("Persistence image auto select %d\n", node->autosel);
2770 return 0;
2771 }
2772
2773 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2774 if (!buf)
2775 {
2776 return 0;
2777 }
2778
2779 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2780 " echo %s\n}\n", "123");
2781
2782 for (i = 0; i < node->backendnum; i++)
2783 {
2784 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2785 " echo 123\n}\n",
2786 node->backendpath[i].path);
2787
2788 }
2789
2790 g_ventoy_menu_esc = 1;
2791 g_ventoy_suppress_esc = 1;
2792
2793 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2794 grub_script_execute_sourcecode(configfile);
2795
2796 g_ventoy_menu_esc = 0;
2797 g_ventoy_suppress_esc = 0;
2798
2799 grub_free(buf);
2800
2801 node->cursel = g_ventoy_last_entry - 1;
2802
2803 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2804 }
2805
2806 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2807 {
2808 grub_uint32_t i;
2809 ventoy_img_chunk *cur;
2810
2811 (void)ctxt;
2812 (void)argc;
2813 (void)args;
2814
2815 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2816 {
2817 cur = g_img_chunk_list.chunk + i;
2818 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2819 cur->img_start_sector, cur->img_end_sector,
2820 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2821 );
2822 }
2823
2824 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2825 }
2826
2827 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2828 {
2829 grub_uint32_t i;
2830 grub_file_t file;
2831 ventoy_img_chunk_list chunklist;
2832
2833 (void)ctxt;
2834 (void)argc;
2835
2836 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2837 if (!file)
2838 {
2839 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2840 }
2841
2842 /* get image chunk data */
2843 grub_memset(&chunklist, 0, sizeof(chunklist));
2844 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2845 if (NULL == chunklist.chunk)
2846 {
2847 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2848 }
2849
2850 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2851 chunklist.cur_chunk = 0;
2852
2853 ventoy_get_block_list(file, &chunklist, 0);
2854
2855 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2856 {
2857 grub_printf("########## UNSUPPORTED ###############\n");
2858 }
2859
2860 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2861
2862 for (i = 0; i < chunklist.cur_chunk; i++)
2863 {
2864 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2865 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2866 }
2867
2868 grub_printf("\n==================================\n");
2869
2870 for (i = 0; i < chunklist.cur_chunk; i++)
2871 {
2872 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2873 (ulonglong)chunklist.chunk[i].img_start_sector,
2874 (ulonglong)chunklist.chunk[i].img_end_sector,
2875 (ulonglong)chunklist.chunk[i].disk_start_sector,
2876 (ulonglong)chunklist.chunk[i].disk_end_sector
2877 );
2878 }
2879
2880 grub_free(chunklist.chunk);
2881 grub_file_close(file);
2882
2883 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2884 }
2885
2886 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2887 {
2888 int i;
2889 ventoy_grub_param_file_replace *replace = NULL;
2890
2891 (void)ctxt;
2892 (void)argc;
2893 (void)args;
2894
2895 if (argc >= 2)
2896 {
2897 replace = &(g_grub_param->file_replace);
2898 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2899
2900 replace->old_name_cnt = 0;
2901 for (i = 0; i < 4 && i + 1 < argc; i++)
2902 {
2903 replace->old_name_cnt++;
2904 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2905 }
2906
2907 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2908 }
2909
2910 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2911 }
2912
2913 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2914 {
2915 (void)ctxt;
2916 (void)argc;
2917 (void)args;
2918
2919 if (argc == 0)
2920 {
2921 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2922 grub_printf("%s", g_list_script_buf);
2923 }
2924 else
2925 {
2926 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2927 grub_printf("%s", g_tree_script_buf);
2928 }
2929
2930 return 0;
2931 }
2932
2933 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2934 {
2935 img_info *cur = g_ventoy_img_list;
2936
2937 (void)ctxt;
2938 (void)argc;
2939 (void)args;
2940
2941 while (cur)
2942 {
2943 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2944 grub_printf("name:<%s>\n\n", cur->name);
2945 cur = cur->next;
2946 }
2947
2948 return 0;
2949 }
2950
2951 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2952 {
2953 (void)ctxt;
2954 (void)argc;
2955 (void)args;
2956
2957 ventoy_plugin_dump_injection();
2958
2959 return 0;
2960 }
2961
2962 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2963 {
2964 (void)ctxt;
2965 (void)argc;
2966 (void)args;
2967
2968 ventoy_plugin_dump_auto_install();
2969
2970 return 0;
2971 }
2972
2973 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2974 {
2975 (void)ctxt;
2976 (void)argc;
2977 (void)args;
2978
2979 ventoy_plugin_dump_persistence();
2980
2981 return 0;
2982 }
2983
2984 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2985 {
2986 (void)ctxt;
2987 (void)argc;
2988 (void)args;
2989
2990 if (argc != 1)
2991 {
2992 return 1;
2993 }
2994
2995 if (args[0][0] == '0')
2996 {
2997 return g_ventoy_memdisk_mode ? 0 : 1;
2998 }
2999 else if (args[0][0] == '1')
3000 {
3001 return g_ventoy_iso_raw ? 0 : 1;
3002 }
3003 else if (args[0][0] == '2')
3004 {
3005 return g_ventoy_iso_uefi_drv ? 0 : 1;
3006 }
3007
3008 return 1;
3009 }
3010
3011 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3012 {
3013 static int configfile_mode = 0;
3014 char memfile[128] = {0};
3015
3016 (void)ctxt;
3017 (void)argc;
3018 (void)args;
3019
3020 /*
3021 * args[0]: 0:normal 1:configfile
3022 * args[1]: 0:list_buf 1:tree_buf
3023 */
3024
3025 if (argc != 2)
3026 {
3027 debug("Invalid argc %d\n", argc);
3028 return 0;
3029 }
3030
3031 if (args[0][0] == '0')
3032 {
3033 if (args[1][0] == '0')
3034 {
3035 grub_script_execute_sourcecode(g_list_script_buf);
3036 }
3037 else
3038 {
3039 grub_script_execute_sourcecode(g_tree_script_buf);
3040 }
3041 }
3042 else
3043 {
3044 if (configfile_mode)
3045 {
3046 debug("Now already in F3 mode %d\n", configfile_mode);
3047 return 0;
3048 }
3049
3050 if (args[1][0] == '0')
3051 {
3052 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3053 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3054 }
3055 else
3056 {
3057 g_ventoy_last_entry = -1;
3058 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3059 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3060 }
3061
3062 configfile_mode = 1;
3063 grub_script_execute_sourcecode(memfile);
3064 configfile_mode = 0;
3065 }
3066
3067 return 0;
3068 }
3069
3070 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3071 {
3072 grub_file_t file;
3073
3074 (void)ctxt;
3075
3076 if (argc != 1)
3077 {
3078 return 1;
3079 }
3080
3081 g_ventoy_case_insensitive = 1;
3082 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3083 g_ventoy_case_insensitive = 0;
3084
3085 grub_errno = 0;
3086
3087 if (file)
3088 {
3089 grub_file_close(file);
3090 return 0;
3091 }
3092 return 1;
3093 }
3094
3095 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3096 {
3097 int id = 0;
3098 int find = 0;
3099 grub_disk_t disk;
3100 const char *isopath = NULL;
3101 char hdname[32];
3102 ventoy_mbr_head mbr;
3103
3104 (void)ctxt;
3105 (void)argc;
3106
3107 if (argc != 1)
3108 {
3109 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3110 }
3111
3112 isopath = grub_env_get("vtoy_iso_part");
3113 if (!isopath)
3114 {
3115 debug("isopath is null %p\n", isopath);
3116 return 0;
3117 }
3118
3119 debug("isopath is %s\n", isopath);
3120
3121 for (id = 0; id < 30 && (find == 0); id++)
3122 {
3123 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3124 if (grub_strstr(isopath, hdname))
3125 {
3126 debug("skip %s ...\n", hdname);
3127 continue;
3128 }
3129
3130 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3131
3132 disk = grub_disk_open(hdname);
3133 if (!disk)
3134 {
3135 debug("%s not exist\n", hdname);
3136 break;
3137 }
3138
3139 grub_memset(&mbr, 0, sizeof(mbr));
3140 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3141 {
3142 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3143 {
3144 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3145 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3146 {
3147
3148 grub_env_set(args[0], hdname);
3149 find = 1;
3150 }
3151 }
3152 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3153 }
3154 else
3155 {
3156 debug("read %s failed\n", hdname);
3157 }
3158
3159 grub_disk_close(disk);
3160 }
3161
3162 return 0;
3163 }
3164
3165 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3166 {
3167 int len = 1024;
3168 grub_file_t file;
3169 char *buf = NULL;
3170
3171 (void)ctxt;
3172 (void)argc;
3173
3174 if (argc != 2)
3175 {
3176 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3177 }
3178
3179 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3180 if (!file)
3181 {
3182 debug("failed to open file %s\n", args[0]);
3183 return 0;
3184 }
3185
3186 buf = grub_malloc(len);
3187 if (!buf)
3188 {
3189 goto end;
3190 }
3191
3192 buf[len - 1] = 0;
3193 grub_file_read(file, buf, len - 1);
3194
3195 ventoy_get_line(buf);
3196 ventoy_set_env(args[1], buf);
3197
3198 end:
3199
3200 grub_check_free(buf);
3201 grub_file_close(file);
3202
3203 return 0;
3204 }
3205
3206 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3207 {
3208 (void)disk;
3209 (void)data;
3210
3211 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3212 "0 %llu linear /dev/ventoy %llu\n",
3213 (ulonglong)partition->len, (ulonglong)partition->start);
3214
3215 return 0;
3216 }
3217
3218 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3219 {
3220 char *device_name = NULL;
3221 grub_device_t dev = NULL;
3222 char buf[64];
3223
3224 (void)ctxt;
3225
3226 g_part_list_pos = 0;
3227 grub_env_unset("vtoy_img_part_file");
3228
3229 if (argc != 1)
3230 {
3231 return 1;
3232 }
3233
3234 device_name = grub_file_get_device_name(args[0]);
3235 if (!device_name)
3236 {
3237 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3238 goto end;
3239 }
3240
3241 dev = grub_device_open(device_name);
3242 if (!dev)
3243 {
3244 debug("grub_device_open failed, %s\n", device_name);
3245 goto end;
3246 }
3247
3248 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3249
3250 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3251 grub_env_set("vtoy_img_part_file", buf);
3252
3253 end:
3254
3255 check_free(device_name, grub_free);
3256 check_free(dev, grub_device_close);
3257
3258 return 0;
3259 }
3260
3261
3262 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3263 {
3264 int rc = 1;
3265 grub_file_t file;
3266 char *buf = NULL;
3267
3268 (void)ctxt;
3269 (void)argc;
3270
3271 if (argc != 2)
3272 {
3273 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3274 }
3275
3276 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3277 if (!file)
3278 {
3279 debug("failed to open file %s\n", args[0]);
3280 return 1;
3281 }
3282
3283 buf = grub_malloc(file->size + 1);
3284 if (!buf)
3285 {
3286 goto end;
3287 }
3288
3289 buf[file->size] = 0;
3290 grub_file_read(file, buf, file->size);
3291
3292 if (grub_strstr(buf, args[1]))
3293 {
3294 rc = 0;
3295 }
3296
3297 end:
3298
3299 grub_check_free(buf);
3300 grub_file_close(file);
3301
3302 return rc;
3303 }
3304
3305 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3306 {
3307 int len;
3308 grub_file_t file;
3309 char buf[64];
3310 grub_uint64_t size;
3311 ventoy_iso9660_vd pvd;
3312
3313 (void)ctxt;
3314 (void)argc;
3315
3316 if (argc != 4)
3317 {
3318 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3319 }
3320
3321 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3322 if (!file)
3323 {
3324 debug("failed to open file %s\n", args[0]);
3325 return 0;
3326 }
3327
3328 grub_file_seek(file, 16 * 2048);
3329 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3330 if (len != sizeof(pvd))
3331 {
3332 debug("failed to read pvd %d\n", len);
3333 goto end;
3334 }
3335
3336 grub_memset(buf, 0, sizeof(buf));
3337 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3338 ventoy_set_env(args[1], buf);
3339
3340 grub_memset(buf, 0, sizeof(buf));
3341 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3342 ventoy_set_env(args[2], buf);
3343
3344 size = pvd.space;
3345 size *= 2048;
3346 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3347 ventoy_set_env(args[3], buf);
3348
3349 end:
3350 grub_file_close(file);
3351
3352 return 0;
3353 }
3354
3355 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3356 {
3357 int len;
3358 grub_file_t file;
3359 char buf[64];
3360
3361 (void)ctxt;
3362 (void)argc;
3363
3364 if (argc != 2)
3365 {
3366 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3367 }
3368
3369 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3370 if (!file)
3371 {
3372 debug("failed to open file %s\n", args[0]);
3373 return 0;
3374 }
3375
3376 grub_memset(buf, 0, sizeof(buf));
3377 grub_file_seek(file, 16 * 2048 + 813);
3378 len = (int)grub_file_read(file, buf, 17);
3379 if (len != 17)
3380 {
3381 debug("failed to read create date %d\n", len);
3382 goto end;
3383 }
3384
3385 ventoy_set_env(args[1], buf);
3386
3387 end:
3388 grub_file_close(file);
3389
3390 return 0;
3391 }
3392
3393 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3394 {
3395 (void)ctxt;
3396 (void)argc;
3397 (void)args;
3398
3399 ventoy_env_hook_root(1);
3400
3401 return 0;
3402 }
3403
3404 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3405 {
3406 (void)ctxt;
3407 (void)argc;
3408 (void)args;
3409
3410 ventoy_env_hook_root(0);
3411
3412 return 0;
3413 }
3414
3415 #ifdef GRUB_MACHINE_EFI
3416 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3417 {
3418 int ret = 1;
3419 grub_uint8_t *var;
3420 grub_size_t size;
3421 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3422
3423 (void)ctxt;
3424 (void)argc;
3425 (void)args;
3426
3427 var = grub_efi_get_variable("SecureBoot", &global, &size);
3428 if (var && *var == 1)
3429 {
3430 return 0;
3431 }
3432
3433 return ret;
3434 }
3435 #else
3436 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3437 {
3438 (void)ctxt;
3439 (void)argc;
3440 (void)args;
3441 return 1;
3442 }
3443 #endif
3444
3445 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3446 {
3447 int i;
3448 int buflen;
3449 int datalen;
3450 int loclen;
3451 int img_chunk_num;
3452 int image_sector_size;
3453 char cmd[64];
3454 ventoy_chain_head *chain;
3455 ventoy_img_chunk *chunk;
3456 ventoy_os_param *osparam;
3457 ventoy_image_location *location;
3458 ventoy_image_disk_region *region;
3459 struct grub_acpi_table_header *acpi;
3460
3461 (void)ctxt;
3462
3463 if (argc != 2)
3464 {
3465 return 1;
3466 }
3467
3468 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3469
3470 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3471 if (!chain)
3472 {
3473 return 1;
3474 }
3475
3476 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3477
3478 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3479 {
3480 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3481 return 1;
3482 }
3483
3484 img_chunk_num = chain->img_chunk_num;
3485
3486 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3487 datalen = sizeof(ventoy_os_param) + loclen;
3488
3489 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3490 acpi = grub_zalloc(buflen);
3491 if (!acpi)
3492 {
3493 return 1;
3494 }
3495
3496 /* Step1: Fill acpi table header */
3497 grub_memcpy(acpi->signature, "VTOY", 4);
3498 acpi->length = buflen;
3499 acpi->revision = 1;
3500 grub_memcpy(acpi->oemid, "VENTOY", 6);
3501 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3502 acpi->oemrev = 1;
3503 acpi->creator_id[0] = 1;
3504 acpi->creator_rev = 1;
3505
3506 /* Step2: Fill data */
3507 osparam = (ventoy_os_param *)(acpi + 1);
3508 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3509 osparam->vtoy_img_location_addr = 0;
3510 osparam->vtoy_img_location_len = loclen;
3511 osparam->chksum = 0;
3512 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3513
3514 location = (ventoy_image_location *)(osparam + 1);
3515 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3516 location->image_sector_size = image_sector_size;
3517 location->disk_sector_size = chain->disk_sector_size;
3518 location->region_count = img_chunk_num;
3519
3520 region = location->regions;
3521 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3522 if (512 == image_sector_size)
3523 {
3524 for (i = 0; i < img_chunk_num; i++)
3525 {
3526 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3527 region->image_start_sector = chunk->img_start_sector * 4;
3528 region->disk_start_sector = chunk->disk_start_sector;
3529 region++;
3530 chunk++;
3531 }
3532 }
3533 else
3534 {
3535 for (i = 0; i < img_chunk_num; i++)
3536 {
3537 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3538 region->image_start_sector = chunk->img_start_sector;
3539 region->disk_start_sector = chunk->disk_start_sector;
3540 region++;
3541 chunk++;
3542 }
3543 }
3544
3545 /* Step3: Fill acpi checksum */
3546 acpi->checksum = 0;
3547 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3548
3549 /* load acpi table */
3550 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3551 grub_script_execute_sourcecode(cmd);
3552
3553 grub_free(acpi);
3554
3555 VENTOY_CMD_RETURN(0);
3556 }
3557
3558 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3559 {
3560 (void)ctxt;
3561 (void)argc;
3562 (void)args;
3563
3564 g_ventoy_last_entry_back = g_ventoy_last_entry;
3565 g_ventoy_last_entry = -1;
3566
3567 return 0;
3568 }
3569
3570 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3571 {
3572 (void)ctxt;
3573 (void)argc;
3574 (void)args;
3575
3576 g_ventoy_last_entry = g_ventoy_last_entry_back;
3577
3578 return 0;
3579 }
3580
3581 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3582 {
3583 grub_uint64_t sectors;
3584
3585 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3586 {
3587 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3588 }
3589 else
3590 {
3591 sectors = gpt->MBR.PartTbl[0].SectorCount;
3592 }
3593
3594 return sectors * 512;
3595 }
3596
3597 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3598 {
3599 const char *pos = filename + 1;
3600
3601 if (info->dir)
3602 {
3603 while (*pos)
3604 {
3605 if (*pos == '.')
3606 {
3607 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3608 {
3609 grub_strncpy((char *)data, filename, 128);
3610 return 1;
3611 }
3612 }
3613 pos++;
3614 }
3615 }
3616
3617 return 0;
3618 }
3619
3620 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3621 {
3622 int rc = 1;
3623 char *device_name = NULL;
3624 grub_device_t dev = NULL;
3625 grub_fs_t fs = NULL;
3626 char buf[128] = {0};
3627
3628 (void)ctxt;
3629
3630 if (argc != 3)
3631 {
3632 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3633 return 1;
3634 }
3635
3636 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3637
3638 device_name = grub_file_get_device_name(args[0]);
3639 if (!device_name)
3640 {
3641 debug("grub_file_get_device_name failed, %s\n", args[0]);
3642 goto end;
3643 }
3644
3645 dev = grub_device_open(device_name);
3646 if (!dev)
3647 {
3648 debug("grub_device_open failed, %s\n", device_name);
3649 goto end;
3650 }
3651
3652 fs = grub_fs_probe(dev);
3653 if (!fs)
3654 {
3655 debug("grub_fs_probe failed, %s\n", device_name);
3656 goto end;
3657 }
3658
3659 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3660
3661 if (buf[0])
3662 {
3663 ventoy_set_env(args[2], buf);
3664 }
3665
3666 rc = 0;
3667
3668 end:
3669
3670 check_free(device_name, grub_free);
3671 check_free(dev, grub_device_close);
3672
3673 return rc;
3674 }
3675
3676 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3677 {
3678 char name[64];
3679 int ret;
3680 grub_disk_t disk;
3681 grub_device_t dev;
3682
3683 (void)argc;
3684 (void)ctxt;
3685
3686 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3687 if (!g_ventoy_part_info)
3688 {
3689 return 1;
3690 }
3691
3692 disk = grub_disk_open(args[0]);
3693 if (!disk)
3694 {
3695 debug("Failed to open disk %s\n", args[0]);
3696 return 1;
3697 }
3698
3699 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3700
3701 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3702 grub_disk_close(disk);
3703
3704 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3705 dev = grub_device_open(name);
3706 if (dev)
3707 {
3708 /* make sure that we are running in a correct Ventoy device */
3709 ret = ventoy_check_device(dev);
3710 grub_device_close(dev);
3711
3712 if (ret)
3713 {
3714 grub_exit();
3715 }
3716 }
3717
3718 return 0;
3719 }
3720
3721 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
3722 {
3723 int ret = 1;
3724 const char *vcfg = NULL;
3725
3726 (void)argc;
3727 (void)ctxt;
3728
3729 vcfg = ventoy_plugin_get_custom_boot(args[0]);
3730 if (vcfg)
3731 {
3732 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
3733 grub_env_set(args[1], vcfg);
3734 ret = 0;
3735 }
3736 else
3737 {
3738 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
3739 }
3740
3741 grub_errno = 0;
3742 return ret;
3743 }
3744
3745
3746 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3747 {
3748 int id;
3749 grub_uint8_t zeroguid[16] = {0};
3750
3751 (void)argc;
3752 (void)ctxt;
3753
3754 id = (int)grub_strtoul(args[0], NULL, 10);
3755 grub_errno = 0;
3756
3757 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3758 {
3759 if (id >= 1 && id <= 128)
3760 {
3761 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3762 {
3763 return 0;
3764 }
3765 }
3766 }
3767 else
3768 {
3769 if (id >= 1 && id <= 4)
3770 {
3771 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3772 {
3773 return 0;
3774 }
3775 }
3776 }
3777
3778 return 1;
3779 }
3780
3781 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3782 {
3783 int rc = 1;
3784 char *device_name = NULL;
3785 grub_device_t dev = NULL;
3786 grub_fs_t fs = NULL;
3787 char *label = NULL;
3788
3789 (void)ctxt;
3790
3791 if (argc != 2)
3792 {
3793 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3794 return 1;
3795 }
3796
3797 device_name = grub_file_get_device_name(args[0]);
3798 if (!device_name)
3799 {
3800 debug("grub_file_get_device_name failed, %s\n", args[0]);
3801 goto end;
3802 }
3803
3804 dev = grub_device_open(device_name);
3805 if (!dev)
3806 {
3807 debug("grub_device_open failed, %s\n", device_name);
3808 goto end;
3809 }
3810
3811 fs = grub_fs_probe(dev);
3812 if (!fs)
3813 {
3814 debug("grub_fs_probe failed, %s\n", device_name);
3815 goto end;
3816 }
3817
3818 fs->fs_label(dev, &label);
3819 if (label)
3820 {
3821 ventoy_set_env(args[1], label);
3822 grub_free(label);
3823 }
3824
3825 rc = 0;
3826
3827 end:
3828
3829 check_free(device_name, grub_free);
3830 check_free(dev, grub_device_close);
3831
3832 return rc;
3833 }
3834
3835 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3836 {
3837 if (!info->dir)
3838 {
3839 grub_snprintf((char *)data, 256, "%s", filename);
3840 return 1;
3841 }
3842
3843 return 0;
3844 }
3845
3846
3847 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3848 {
3849 int rc = 1;
3850 char *device_name = NULL;
3851 grub_device_t dev = NULL;
3852 grub_fs_t fs = NULL;
3853 char name[256] ={0};
3854
3855 (void)ctxt;
3856
3857 if (argc != 3)
3858 {
3859 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3860 return 1;
3861 }
3862
3863 device_name = grub_file_get_device_name(args[0]);
3864 if (!device_name)
3865 {
3866 debug("grub_file_get_device_name failed, %s\n", args[0]);
3867 goto end;
3868 }
3869
3870 dev = grub_device_open(device_name);
3871 if (!dev)
3872 {
3873 debug("grub_device_open failed, %s\n", device_name);
3874 goto end;
3875 }
3876
3877 fs = grub_fs_probe(dev);
3878 if (!fs)
3879 {
3880 debug("grub_fs_probe failed, %s\n", device_name);
3881 goto end;
3882 }
3883
3884 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3885 if (name[0])
3886 {
3887 ventoy_set_env(args[2], name);
3888 }
3889
3890 rc = 0;
3891
3892 end:
3893
3894 check_free(device_name, grub_free);
3895 check_free(dev, grub_device_close);
3896
3897 return rc;
3898 }
3899
3900 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3901 {
3902 char c;
3903 char *pos = NULL;
3904 char *end = NULL;
3905
3906 (void)ctxt;
3907
3908 if (argc != 2)
3909 {
3910 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3911 return 1;
3912 }
3913
3914 for (pos = args[0]; *pos; pos++)
3915 {
3916 if (*pos == '.')
3917 {
3918 end = pos;
3919 }
3920 }
3921
3922 if (end)
3923 {
3924 c = *end;
3925 *end = 0;
3926 }
3927
3928 grub_env_set(args[1], args[0]);
3929
3930 if (end)
3931 {
3932 *end = c;
3933 }
3934
3935 return 0;
3936 }
3937
3938 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
3939 {
3940 int i;
3941 int len;
3942 const char *buf;
3943
3944 (void)ctxt;
3945
3946 if (argc != 2)
3947 {
3948 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
3949 return 1;
3950 }
3951
3952 buf = args[0];
3953 len = (int)grub_strlen(buf);
3954 for (i = len; i > 0; i--)
3955 {
3956 if (buf[i - 1] == '/')
3957 {
3958 grub_env_set(args[1], buf + i);
3959 return 0;
3960 }
3961 }
3962
3963 grub_env_set(args[1], buf);
3964
3965 return 0;
3966 }
3967
3968 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3969 {
3970 struct grub_video_mode_info info;
3971 char buf[32];
3972
3973 (void)ctxt;
3974 (void)argc;
3975 (void)args;
3976
3977 if (!g_video_mode_list)
3978 {
3979 ventoy_enum_video_mode();
3980 }
3981
3982 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3983 {
3984 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3985 }
3986 else
3987 {
3988 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3989 }
3990
3991 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3992
3993 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3994 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3995
3996 VENTOY_CMD_RETURN(0);
3997 }
3998
3999 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4000 {
4001 struct grub_video_mode_info info;
4002 char buf[32];
4003
4004 (void)ctxt;
4005 (void)argc;
4006 (void)args;
4007
4008 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4009 {
4010 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4011 }
4012 else
4013 {
4014 grub_snprintf(buf, sizeof(buf), "0x0x0");
4015 }
4016
4017 grub_env_set(args[0], buf);
4018
4019 VENTOY_CMD_RETURN(0);
4020 }
4021
4022 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4023 {
4024 int id;
4025 char buf[32];
4026
4027 (void)ctxt;
4028 (void)argc;
4029
4030 if (!g_video_mode_list)
4031 {
4032 return 0;
4033 }
4034
4035 id = (int)grub_strtoul(args[0], NULL, 10);
4036 if (id < g_video_mode_num)
4037 {
4038 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4039 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4040 }
4041
4042 grub_env_set(args[1], buf);
4043
4044 VENTOY_CMD_RETURN(0);
4045 }
4046
4047 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
4048 {
4049 grub_uint64_t size = 0;
4050 grub_file_t file;
4051 va_list ap;
4052 char fullpath[256] = {0};
4053
4054 va_start (ap, fmt);
4055 grub_vsnprintf(fullpath, 255, fmt, ap);
4056 va_end (ap);
4057
4058 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
4059 if (!file)
4060 {
4061 debug("grub_file_open failed <%s>\n", fullpath);
4062 grub_errno = 0;
4063 return 0;
4064 }
4065
4066 size = file->size;
4067 grub_file_close(file);
4068 return size;
4069 }
4070
4071 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
4072 {
4073 va_list ap;
4074 grub_file_t file;
4075 char fullpath[256] = {0};
4076
4077 va_start (ap, fmt);
4078 grub_vsnprintf(fullpath, 255, fmt, ap);
4079 va_end (ap);
4080
4081 file = grub_file_open(fullpath, type);
4082 if (!file)
4083 {
4084 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
4085 grub_errno = 0;
4086 }
4087
4088 return file;
4089 }
4090
4091 int ventoy_is_file_exist(const char *fmt, ...)
4092 {
4093 va_list ap;
4094 int len;
4095 char *pos = NULL;
4096 char buf[256] = {0};
4097
4098 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
4099 pos = buf + 6;
4100
4101 va_start (ap, fmt);
4102 len = grub_vsnprintf(pos, 255, fmt, ap);
4103 va_end (ap);
4104
4105 grub_strncpy(pos + len, "\" ]", 3);
4106
4107 debug("script exec %s\n", buf);
4108
4109 if (0 == grub_script_execute_sourcecode(buf))
4110 {
4111 return 1;
4112 }
4113
4114 return 0;
4115 }
4116
4117 int ventoy_is_dir_exist(const char *fmt, ...)
4118 {
4119 va_list ap;
4120 int len;
4121 char *pos = NULL;
4122 char buf[256] = {0};
4123
4124 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
4125 pos = buf + 6;
4126
4127 va_start (ap, fmt);
4128 len = grub_vsnprintf(pos, 255, fmt, ap);
4129 va_end (ap);
4130
4131 grub_strncpy(pos + len, "\" ]", 3);
4132
4133 debug("script exec %s\n", buf);
4134
4135 if (0 == grub_script_execute_sourcecode(buf))
4136 {
4137 return 1;
4138 }
4139
4140 return 0;
4141 }
4142
4143 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
4144 {
4145 mz_stream s;
4146 grub_uint8_t *outbuf;
4147 grub_uint8_t gzHdr[10] =
4148 {
4149 0x1F, 0x8B, /* magic */
4150 8, /* z method */
4151 0, /* flags */
4152 0,0,0,0, /* mtime */
4153 4, /* xfl */
4154 3, /* OS */
4155 };
4156
4157 grub_memset(&s, 0, sizeof(mz_stream));
4158
4159 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
4160
4161 outbuf = (grub_uint8_t *)mem_out;
4162
4163 mem_out_len -= sizeof(gzHdr) + 8;
4164 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
4165 outbuf += sizeof(gzHdr);
4166
4167 s.avail_in = mem_in_len;
4168 s.next_in = mem_in;
4169
4170 s.avail_out = mem_out_len;
4171 s.next_out = outbuf;
4172
4173 mz_deflate(&s, MZ_FINISH);
4174
4175 mz_deflateEnd(&s);
4176
4177 outbuf += s.total_out;
4178 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4179 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4180
4181 return s.total_out + sizeof(gzHdr) + 8;
4182 }
4183
4184 static int ventoy_env_init(void)
4185 {
4186 char buf[64];
4187
4188 grub_env_set("vtdebug_flag", "");
4189
4190 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4191 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4192 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4193 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4194
4195 ventoy_filt_register(0, ventoy_wrapper_open);
4196
4197 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4198 if (g_grub_param)
4199 {
4200 g_grub_param->grub_env_get = grub_env_get;
4201 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4202 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4203 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4204 grub_env_set("env_param", buf);
4205 grub_env_set("ventoy_env_param", buf);
4206 grub_env_export("ventoy_env_param");
4207 }
4208
4209 return 0;
4210 }
4211
4212 static cmd_para ventoy_cmds[] =
4213 {
4214 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4215 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4216 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4217 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4218 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4219 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4220 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4221 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4222 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4223 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4224 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4225 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4226 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4227 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4228 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4229 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4230 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4231 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4232 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4233 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4234 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4235 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4236 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4237
4238 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4239 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4240 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4241 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4242 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4243 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4244 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4245
4246 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4247 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4248 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4249 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4250 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4251 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4252 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4253 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4254 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4255
4256
4257 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4258 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4259 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4260 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4261 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4262 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4263 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4264 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4265 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4266 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4267 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4268
4269 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4270 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4271 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4272 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4273 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4274 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4275
4276 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4277 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4278 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4279 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4280 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4281 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4282 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4283 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4284 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4285 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4286
4287 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4288 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4289 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4290 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4291 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4292 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4293 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4294 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4295
4296 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4297 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4298 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4299
4300
4301 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4302 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4303 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4304
4305 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4306 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4307 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4308
4309
4310 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4311 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4312 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4313 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4314 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4315 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4316 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4317 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4318 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4319 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4320
4321 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4322 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4323 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4324 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4325
4326 };
4327
4328
4329
4330 GRUB_MOD_INIT(ventoy)
4331 {
4332 grub_uint32_t i;
4333 cmd_para *cur = NULL;
4334
4335 ventoy_env_init();
4336
4337 ventoy_arch_mode_init();
4338
4339 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4340 {
4341 cur = ventoy_cmds + i;
4342 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4343 cur->summary, cur->description, cur->parser);
4344 }
4345 }
4346
4347 GRUB_MOD_FINI(ventoy)
4348 {
4349 grub_uint32_t i;
4350
4351 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4352 {
4353 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4354 }
4355 }
4356