]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
Add VTOY_MAX_SEARCH_LEVEL option in global control plugin
[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
1431 {
1432 g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI;
1433 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi");
1434 }
1435 #else
1436 g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY;
1437 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy");
1438 #endif
1439
1440 return 0;
1441 }
1442
1443 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1444 {
1445 int len = GRUB_UINT_MAX;
1446 const char *value = NULL;
1447 char name[32] = {0};
1448 char plat[32] = {0};
1449 char guidstr[32] = {0};
1450 ventoy_guid guid = VENTOY_GUID;
1451 const char *fmt1 = NULL;
1452 const char *fmt2 = NULL;
1453 const char *fmt3 = NULL;
1454 grub_uint32_t *puint = (grub_uint32_t *)name;
1455 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1456 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1457 const char fmtcode[]={
1458 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1459 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1460 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1461 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1462 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1463 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1464 };
1465
1466 grub_memset(name, 0, sizeof(name));
1467 puint[0] = grub_swap_bytes32(0x56454e54);
1468 puint[3] = grub_swap_bytes32(0x4f4e0000);
1469 puint[2] = grub_swap_bytes32(0x45525349);
1470 puint[1] = grub_swap_bytes32(0x4f595f56);
1471 value = ventoy_get_env(name);
1472
1473 grub_memset(name, 0, sizeof(name));
1474 puint[1] = grub_swap_bytes32(0x5f544f50);
1475 puint[0] = grub_swap_bytes32(0x56544c45);
1476 fmt1 = ventoy_get_env(name);
1477 if (!fmt1)
1478 {
1479 fmt1 = fmtdata;
1480 }
1481
1482 grub_memset(name, 0, sizeof(name));
1483 puint[1] = grub_swap_bytes32(0x5f4c4654);
1484 puint[0] = grub_swap_bytes32(0x56544c45);
1485 fmt2 = ventoy_get_env(name);
1486
1487 grub_memset(name, 0, sizeof(name));
1488 puint[1] = grub_swap_bytes32(0x5f434c52);
1489 puint[0] = grub_swap_bytes32(0x56544c45);
1490 fmt3 = ventoy_get_env(name);
1491
1492 grub_memcpy(guidstr, &guid, sizeof(guid));
1493
1494 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1495
1496 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1497 #pragma GCC diagnostic push
1498 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1499 len = grub_snprintf(buffer, buflen, fmtcode,
1500 fmt1 ? fmt1 : fmtdata,
1501 fmt2 ? fmt2 : fmtdata + 4,
1502 value ? value : "", plat, guidstr,
1503 fmt3 ? fmt3 : fmtdata + 6);
1504 #pragma GCC diagnostic pop
1505
1506 grub_memset(name, 0, sizeof(name));
1507 puint[0] = grub_swap_bytes32(0x76746f79);
1508 puint[2] = grub_swap_bytes32(0x656e7365);
1509 puint[1] = grub_swap_bytes32(0x5f6c6963);
1510 ventoy_set_env(name, guidstr);
1511
1512 return len;
1513 }
1514
1515 int ventoy_check_password(const vtoy_password *pwd, int retry)
1516 {
1517 int offset;
1518 char input[256];
1519 grub_uint8_t md5[16];
1520
1521 while (retry--)
1522 {
1523 grub_memset(input, 0, sizeof(input));
1524
1525 grub_printf("Enter password: ");
1526 grub_refresh();
1527
1528 if (pwd->type == VTOY_PASSWORD_TXT)
1529 {
1530 grub_password_get(input, 128);
1531 if (grub_strcmp(pwd->text, input) == 0)
1532 {
1533 return 0;
1534 }
1535 }
1536 else if (pwd->type == VTOY_PASSWORD_MD5)
1537 {
1538 grub_password_get(input, 128);
1539 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1540 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1541 {
1542 return 0;
1543 }
1544 }
1545 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1546 {
1547 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1548 grub_password_get(input + offset, 128);
1549
1550 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1551 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1552 {
1553 return 0;
1554 }
1555 }
1556
1557 grub_printf("Invalid password!\n\n");
1558 grub_refresh();
1559 }
1560
1561 return 1;
1562 }
1563
1564 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1565 {
1566 img_info *minimg = NULL;
1567 img_info *img = (img_info *)(node->firstiso);
1568
1569 while (img && (img_iterator_node *)(img->parent) == node)
1570 {
1571 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1572 {
1573 minimg = img;
1574 }
1575 img = img->next;
1576 }
1577
1578 if (minimg)
1579 {
1580 minimg->select = 1;
1581 }
1582
1583 return minimg;
1584 }
1585
1586 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1587 {
1588 img_iterator_node *Minchild = NULL;
1589 img_iterator_node *child = node->firstchild;
1590
1591 while (child && child->parent == node)
1592 {
1593 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1594 {
1595 Minchild = child;
1596 }
1597 child = child->next;
1598 }
1599
1600 if (Minchild)
1601 {
1602 Minchild->select = 1;
1603 }
1604
1605 return Minchild;
1606 }
1607
1608 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1609 {
1610 int offset = 1;
1611 img_info *img = NULL;
1612 const char *dir_class = NULL;
1613 const char *dir_alias = NULL;
1614 img_iterator_node *child = NULL;
1615
1616 if (node->isocnt == 0 || node->done == 1)
1617 {
1618 return 0;
1619 }
1620
1621 if (node->parent && node->parent->dirlen < node->dirlen)
1622 {
1623 offset = node->parent->dirlen;
1624 }
1625
1626 if (node == &g_img_iterator_head)
1627 {
1628 if (g_default_menu_mode == 0)
1629 {
1630 if (g_tree_view_menu_style == 0)
1631 {
1632 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1633 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1634 " echo 'return ...' \n"
1635 "}\n", "<--");
1636 }
1637 else
1638 {
1639 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1640 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1641 " echo '%s ...' \n"
1642 "}\n", "return");
1643 }
1644 }
1645 }
1646 else
1647 {
1648 node->dir[node->dirlen - 1] = 0;
1649 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1650 if (!dir_class)
1651 {
1652 dir_class = "vtoydir";
1653 }
1654
1655 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1656 if (dir_alias)
1657 {
1658 if (g_tree_view_menu_style == 0)
1659 {
1660 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1661 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1662 "DIR", dir_alias, dir_class, node->dir + offset);
1663 }
1664 else
1665 {
1666 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1667 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1668 dir_alias, dir_class, node->dir + offset);
1669 }
1670 }
1671 else
1672 {
1673 dir_alias = node->dir + offset;
1674
1675 if (g_tree_view_menu_style == 0)
1676 {
1677 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1678 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1679 "DIR", dir_alias, dir_class, node->dir + offset);
1680 }
1681 else
1682 {
1683 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1684 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1685 dir_alias, dir_class, node->dir + offset);
1686 }
1687 }
1688
1689 if (g_tree_view_menu_style == 0)
1690 {
1691 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1692 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1693 " echo 'return ...' \n"
1694 "}\n", "<--");
1695 }
1696 else
1697 {
1698 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1699 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1700 " echo '%s ...' \n"
1701 "}\n", "return");
1702 }
1703 }
1704
1705 while ((child = ventoy_get_min_child(node)) != NULL)
1706 {
1707 ventoy_dynamic_tree_menu(child);
1708 }
1709
1710 while ((img = ventoy_get_min_iso(node)) != NULL)
1711 {
1712 if (g_tree_view_menu_style == 0)
1713 {
1714 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1715 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1716 " %s_%s \n"
1717 "}\n",
1718 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1719 img->unsupport ? "[***********] " : "",
1720 img->alias ? img->alias : img->name, img->class, img->id,
1721 img->menu_prefix,
1722 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1723 }
1724 else
1725 {
1726 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1727 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1728 " %s_%s \n"
1729 "}\n",
1730 img->unsupport ? "[***********] " : "",
1731 img->alias ? img->alias : img->name, img->class, img->id,
1732 img->menu_prefix,
1733 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1734 }
1735 }
1736
1737 if (node != &g_img_iterator_head)
1738 {
1739 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1740 }
1741
1742 node->done = 1;
1743 return 0;
1744 }
1745
1746 int ventoy_check_device_result(int ret)
1747 {
1748 char buf[32];
1749
1750 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1751 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1752 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1753
1754 if (ret)
1755 {
1756 grub_printf(VTOY_WARNING"\n");
1757 grub_printf(VTOY_WARNING"\n");
1758 grub_printf(VTOY_WARNING"\n\n\n");
1759
1760 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1761 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1762
1763 grub_printf("\n\nWill exit after 10 seconds ...... ");
1764 grub_refresh();
1765 grub_sleep(10);
1766 }
1767
1768 return ret;
1769 }
1770
1771 int ventoy_check_device(grub_device_t dev)
1772 {
1773 int workaround = 0;
1774 grub_file_t file;
1775 grub_uint64_t offset;
1776 char devname[64];
1777 grub_fs_t fs;
1778 grub_device_t dev2;
1779 char *label = NULL;
1780 struct grub_partition *partition;
1781
1782 if (dev->disk == NULL || dev->disk->partition == NULL)
1783 {
1784 return ventoy_check_device_result(1 | 0x1000);
1785 }
1786
1787 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1788 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1789 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1790 {
1791 #ifndef GRUB_MACHINE_EFI
1792 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
1793 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
1794 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1795 {
1796 return ventoy_check_device_result(2 | 0x1000);
1797 }
1798 else
1799 {
1800 workaround = 1;
1801 }
1802 #endif
1803 }
1804
1805 /* We must have partition 2 */
1806 if (workaround)
1807 {
1808 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1809 }
1810 else
1811 {
1812 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1813 }
1814 if (!file)
1815 {
1816 return ventoy_check_device_result(3 | 0x1000);
1817 }
1818
1819 if (NULL == grub_strstr(file->fs->name, "fat"))
1820 {
1821 grub_file_close(file);
1822 return ventoy_check_device_result(4 | 0x1000);
1823 }
1824
1825 partition = dev->disk->partition;
1826 if (partition->number != 0 || partition->start != 2048)
1827 {
1828 return ventoy_check_device_result(5);
1829 }
1830
1831 if (workaround)
1832 {
1833 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
1834 {
1835 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
1836 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
1837 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
1838 {
1839 grub_file_close(file);
1840 return ventoy_check_device_result(6);
1841 }
1842 }
1843 else
1844 {
1845 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
1846 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
1847 PartTbl[1].SectorCount != 65536)
1848 {
1849 grub_file_close(file);
1850 return ventoy_check_device_result(6);
1851 }
1852 }
1853 }
1854 else
1855 {
1856 offset = partition->start + partition->len;
1857 partition = file->device->disk->partition;
1858 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1859 {
1860 grub_file_close(file);
1861 return ventoy_check_device_result(7);
1862 }
1863 }
1864
1865 grub_file_close(file);
1866
1867 if (workaround == 0)
1868 {
1869 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1870 dev2 = grub_device_open(devname);
1871 if (!dev2)
1872 {
1873 return ventoy_check_device_result(8);
1874 }
1875
1876 fs = grub_fs_probe(dev2);
1877 if (!fs)
1878 {
1879 grub_device_close(dev2);
1880 return ventoy_check_device_result(9);
1881 }
1882
1883 fs->fs_label(dev2, &label);
1884 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1885 {
1886 grub_device_close(dev2);
1887 return ventoy_check_device_result(10);
1888 }
1889
1890 grub_device_close(dev2);
1891 }
1892
1893 return ventoy_check_device_result(0);
1894 }
1895
1896 static int ventoy_set_default_menu(void)
1897 {
1898 int img_len = 0;
1899 char *pos = NULL;
1900 char *end = NULL;
1901 char *def = NULL;
1902 const char *strdata = NULL;
1903 img_info *cur = NULL;
1904 img_info *default_node = NULL;
1905 const char *default_image = NULL;
1906
1907 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1908 if (default_image && default_image[0] == '/')
1909 {
1910 img_len = grub_strlen(default_image);
1911
1912 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1913 {
1914 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1915 {
1916 default_node = cur;
1917 break;
1918 }
1919 }
1920
1921 if (!default_node)
1922 {
1923 return 1;
1924 }
1925
1926 if (0 == g_default_menu_mode)
1927 {
1928 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1929 }
1930 else
1931 {
1932 def = grub_strdup(default_image);
1933 if (!def)
1934 {
1935 return 1;
1936 }
1937
1938 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1939
1940 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1941 if (strdata && strdata[0] == '/')
1942 {
1943 pos = def + grub_strlen(strdata);
1944 if (*pos == '/')
1945 {
1946 pos++;
1947 }
1948 }
1949 else
1950 {
1951 pos = def + 1;
1952 }
1953
1954 while ((end = grub_strchr(pos, '/')) != NULL)
1955 {
1956 *end = 0;
1957 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1958 pos = end + 1;
1959 }
1960
1961 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1962 grub_free(def);
1963 }
1964 }
1965
1966 return 0;
1967 }
1968
1969 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1970 {
1971 int len;
1972 grub_fs_t fs;
1973 grub_device_t dev = NULL;
1974 img_info *cur = NULL;
1975 img_info *tail = NULL;
1976 const char *strdata = NULL;
1977 char *device_name = NULL;
1978 char buf[32];
1979 img_iterator_node *node = NULL;
1980 img_iterator_node *tmp = NULL;
1981
1982 (void)ctxt;
1983
1984 if (argc != 2)
1985 {
1986 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1987 }
1988
1989 if (g_ventoy_img_list || g_ventoy_img_count)
1990 {
1991 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1992 }
1993
1994 g_enumerate_time_checked = 0;
1995 g_enumerate_start_time_ms = grub_get_time_ms();
1996
1997 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1998 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1999 {
2000 g_filt_dot_underscore_file = 1;
2001 }
2002
2003 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2004 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2005 {
2006 g_sort_case_sensitive = 1;
2007 }
2008
2009 device_name = grub_file_get_device_name(args[0]);
2010 if (!device_name)
2011 {
2012 goto fail;
2013 }
2014
2015 g_enum_dev = dev = grub_device_open(device_name);
2016 if (!dev)
2017 {
2018 goto fail;
2019 }
2020
2021 g_enum_fs = fs = grub_fs_probe(dev);
2022 if (!fs)
2023 {
2024 goto fail;
2025 }
2026
2027 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2028 {
2029 debug("unsupported fs:<%s>\n", fs->name);
2030 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2031 goto fail;
2032 }
2033
2034 ventoy_set_env("vtoy_iso_fs", fs->name);
2035
2036 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2037 if (strdata && strdata[0] == '1')
2038 {
2039 g_default_menu_mode = 1;
2040 }
2041
2042 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2043
2044 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2045
2046 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2047 if (strdata && strdata[0] == '/')
2048 {
2049 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2050 if (g_img_iterator_head.dir[len - 1] != '/')
2051 {
2052 g_img_iterator_head.dir[len++] = '/';
2053 }
2054 g_img_iterator_head.dirlen = len;
2055 }
2056 else
2057 {
2058 g_img_iterator_head.dirlen = 1;
2059 grub_strcpy(g_img_iterator_head.dir, "/");
2060 }
2061
2062 g_img_iterator_head.tail = &tail;
2063
2064 if (g_img_max_search_level < 0)
2065 {
2066 g_img_max_search_level = GRUB_INT_MAX;
2067 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2068 if (strdata && ventoy_is_decimal(strdata))
2069 {
2070 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2071 }
2072 }
2073
2074 for (node = &g_img_iterator_head; node; node = node->next)
2075 {
2076 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2077 }
2078
2079 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2080 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2081 {
2082 g_tree_view_menu_style = 1;
2083 }
2084
2085 ventoy_set_default_menu();
2086
2087 for (node = &g_img_iterator_head; node; node = node->next)
2088 {
2089 ventoy_dynamic_tree_menu(node);
2090 }
2091
2092 /* free node */
2093 node = g_img_iterator_head.next;
2094 while (node)
2095 {
2096 tmp = node->next;
2097 grub_free(node);
2098 node = tmp;
2099 }
2100
2101 /* sort image list by image name */
2102 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2103 {
2104 for (tail = cur->next; tail; tail = tail->next)
2105 {
2106 if (ventoy_cmp_img(cur, tail) > 0)
2107 {
2108 ventoy_swap_img(cur, tail);
2109 }
2110 }
2111 }
2112
2113 if (g_default_menu_mode == 1)
2114 {
2115 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2116 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2117 " echo 'return ...' \n"
2118 "}\n", "<--");
2119 }
2120
2121 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2122 {
2123 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2124 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2125 " %s_%s \n"
2126 "}\n",
2127 cur->unsupport ? "[***********] " : "",
2128 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2129 cur->menu_prefix,
2130 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2131 }
2132
2133 g_tree_script_buf[g_tree_script_pos] = 0;
2134 g_list_script_buf[g_list_script_pos] = 0;
2135
2136 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2137 grub_env_set(args[1], buf);
2138
2139 fail:
2140
2141 check_free(device_name, grub_free);
2142 check_free(dev, grub_device_close);
2143
2144 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2145 }
2146
2147
2148 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2149 {
2150 img_info *next = NULL;
2151 img_info *cur = g_ventoy_img_list;
2152
2153 (void)ctxt;
2154 (void)argc;
2155 (void)args;
2156
2157 while (cur)
2158 {
2159 next = cur->next;
2160 grub_free(cur);
2161 cur = next;
2162 }
2163
2164 g_ventoy_img_list = NULL;
2165 g_ventoy_img_count = 0;
2166
2167 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2168 }
2169
2170 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2171 {
2172 long img_id = 0;
2173 img_info *cur = g_ventoy_img_list;
2174
2175 (void)ctxt;
2176
2177 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2178 {
2179 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2180 }
2181
2182 img_id = grub_strtol(args[0], NULL, 10);
2183 if (img_id >= g_ventoy_img_count)
2184 {
2185 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2186 }
2187
2188 debug("Find image %ld name \n", img_id);
2189
2190 while (cur && img_id > 0)
2191 {
2192 img_id--;
2193 cur = cur->next;
2194 }
2195
2196 if (!cur)
2197 {
2198 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2199 }
2200
2201 debug("image name is %s\n", cur->name);
2202
2203 grub_env_set(args[1], cur->name);
2204
2205 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2206 }
2207
2208 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2209 {
2210 int img_id = 0;
2211 char value[32];
2212 char *pos = NULL;
2213 const char *id = NULL;
2214 img_info *cur = g_ventoy_img_list;
2215
2216 (void)ctxt;
2217
2218 if (argc < 1 || argc > 2)
2219 {
2220 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2221 }
2222
2223 id = grub_env_get("chosen");
2224
2225 pos = grub_strstr(id, "VID_");
2226 if (pos)
2227 {
2228 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2229 }
2230 else
2231 {
2232 img_id = (int)grub_strtoul(id, NULL, 10);
2233 }
2234
2235 while (cur)
2236 {
2237 if (img_id == cur->id)
2238 {
2239 break;
2240 }
2241 cur = cur->next;
2242 }
2243
2244 if (!cur)
2245 {
2246 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2247 }
2248
2249 grub_env_set(args[0], cur->path);
2250
2251 if (argc > 1)
2252 {
2253 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2254 grub_env_set(args[1], value);
2255 }
2256
2257 g_svd_replace_offset = 0;
2258
2259 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2260 }
2261
2262 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2263 {
2264 grub_disk_t disk;
2265 char *device_name;
2266 char *pos;
2267 char *pos2;
2268
2269 device_name = grub_file_get_device_name(filename);
2270 if (!device_name)
2271 {
2272 return 1;
2273 }
2274
2275 pos = device_name;
2276 if (pos[0] == '(')
2277 {
2278 pos++;
2279 }
2280
2281 pos2 = grub_strstr(pos, ",");
2282 if (!pos2)
2283 {
2284 pos2 = grub_strstr(pos, ")");
2285 }
2286
2287 if (pos2)
2288 {
2289 *pos2 = 0;
2290 }
2291
2292 disk = grub_disk_open(pos);
2293 if (disk)
2294 {
2295 grub_disk_read(disk, 0, 0x180, 16, guid);
2296 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2297 grub_disk_close(disk);
2298 }
2299 else
2300 {
2301 return 1;
2302 }
2303
2304 grub_free(device_name);
2305 return 0;
2306 }
2307
2308 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2309 {
2310 eltorito_descriptor desc;
2311
2312 grub_memset(&desc, 0, sizeof(desc));
2313 grub_file_seek(file, 17 * 2048);
2314 grub_file_read(file, &desc, sizeof(desc));
2315
2316 if (desc.type != 0 || desc.version != 1)
2317 {
2318 return 0;
2319 }
2320
2321 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2322 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2323 {
2324 return 0;
2325 }
2326
2327 return desc.sector;
2328 }
2329
2330 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2331 {
2332 int i;
2333 int x86count = 0;
2334 grub_uint8_t buf[512];
2335 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2336
2337 grub_file_seek(file, sector * 2048);
2338 grub_file_read(file, buf, sizeof(buf));
2339
2340 if (buf[0] == 0x01 && buf[1] == 0xEF)
2341 {
2342 debug("%s efi eltorito in Validation Entry\n", file->name);
2343 return 1;
2344 }
2345
2346 if (buf[0] == 0x01 && buf[1] == 0x00)
2347 {
2348 x86count++;
2349 }
2350
2351 for (i = 64; i < (int)sizeof(buf); i += 32)
2352 {
2353 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2354 {
2355 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2356 return 1;
2357 }
2358
2359 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2360 {
2361 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2362 return 1;
2363 }
2364 }
2365
2366 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2367 {
2368 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2369 {
2370 if (buf[36] == parttype[i])
2371 {
2372 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2373 return 1;
2374 }
2375 }
2376 }
2377
2378 debug("%s does not contain efi eltorito\n", file->name);
2379 return 0;
2380 }
2381
2382 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2383 {
2384 char *pos;
2385 const char *fs = NULL;
2386 const char *cdprompt = NULL;
2387 grub_uint32_t i;
2388 grub_uint8_t chksum = 0;
2389 grub_disk_t disk;
2390
2391 disk = file->device->disk;
2392 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2393
2394 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2395 param->vtoy_disk_part_id = disk->partition->number + 1;
2396 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2397
2398 pos = grub_strstr(file->name, "/");
2399 if (!pos)
2400 {
2401 pos = file->name;
2402 }
2403
2404 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2405
2406 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2407
2408 param->vtoy_img_size = file->size;
2409
2410 param->vtoy_reserved[0] = g_ventoy_break_level;
2411 param->vtoy_reserved[1] = g_ventoy_debug_level;
2412
2413 param->vtoy_reserved[2] = g_ventoy_chain_type;
2414
2415 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2416 param->vtoy_reserved[4] = 0;
2417 if (g_ventoy_chain_type == 1) /* Windows */
2418 {
2419 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2420 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2421 {
2422 param->vtoy_reserved[4] = 1;
2423 }
2424 }
2425
2426 fs = ventoy_get_env("ventoy_fs_probe");
2427 if (fs && grub_strcmp(fs, "udf") == 0)
2428 {
2429 param->vtoy_reserved[3] = 1;
2430 }
2431
2432 /* calculate checksum */
2433 for (i = 0; i < sizeof(ventoy_os_param); i++)
2434 {
2435 chksum += *((grub_uint8_t *)param + i);
2436 }
2437 param->chksum = (grub_uint8_t)(0x100 - chksum);
2438
2439 return;
2440 }
2441
2442 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2443 {
2444 grub_uint32_t i = 0;
2445 grub_uint64_t total = 0;
2446 ventoy_img_chunk *chunk = NULL;
2447
2448 for (i = 0; i < chunklist->cur_chunk; i++)
2449 {
2450 chunk = chunklist->chunk + i;
2451
2452 if (chunk->disk_start_sector <= start)
2453 {
2454 debug("%u disk start invalid %lu\n", i, (ulong)start);
2455 return 1;
2456 }
2457
2458 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2459 }
2460
2461 if (total != ((file->size + 511) / 512))
2462 {
2463 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2464 return 1;
2465 }
2466
2467 return 0;
2468 }
2469
2470 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2471 {
2472 int fs_type;
2473 int len;
2474 grub_uint32_t i = 0;
2475 grub_uint32_t sector = 0;
2476 grub_uint32_t count = 0;
2477 grub_off_t size = 0;
2478 grub_off_t read = 0;
2479
2480 fs_type = ventoy_get_fs_type(file->fs->name);
2481 if (fs_type == ventoy_fs_exfat)
2482 {
2483 grub_fat_get_file_chunk(start, file, chunklist);
2484 }
2485 else if (fs_type == ventoy_fs_ext)
2486 {
2487 grub_ext_get_file_chunk(start, file, chunklist);
2488 }
2489 else
2490 {
2491 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2492 file->read_hook_data = chunklist;
2493
2494 for (size = file->size; size > 0; size -= read)
2495 {
2496 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2497 grub_file_read(file, NULL, read);
2498 }
2499
2500 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2501 {
2502 chunklist->chunk[i].disk_start_sector += start;
2503 chunklist->chunk[i].disk_end_sector += start;
2504 }
2505
2506 if (ventoy_fs_udf == fs_type)
2507 {
2508 for (i = 0; i < chunklist->cur_chunk; i++)
2509 {
2510 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2511 chunklist->chunk[i].img_start_sector = sector;
2512 chunklist->chunk[i].img_end_sector = sector + count - 1;
2513 sector += count;
2514 }
2515 }
2516 }
2517
2518 len = (int)grub_strlen(file->name);
2519 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2520 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2521 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2522 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2523 {
2524 for (i = 0; i < chunklist->cur_chunk; i++)
2525 {
2526 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2527 if (count < 4)
2528 {
2529 count = 1;
2530 }
2531 else
2532 {
2533 count >>= 2;
2534 }
2535
2536 chunklist->chunk[i].img_start_sector = sector;
2537 chunklist->chunk[i].img_end_sector = sector + count - 1;
2538 sector += count;
2539 }
2540 }
2541
2542 return 0;
2543 }
2544
2545 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2546 {
2547 int rc;
2548 grub_file_t file;
2549 grub_disk_addr_t start;
2550
2551 (void)ctxt;
2552 (void)argc;
2553
2554 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2555 if (!file)
2556 {
2557 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2558 }
2559
2560 g_conf_replace_node = NULL;
2561 g_conf_replace_offset = 0;
2562
2563 if (g_img_chunk_list.chunk)
2564 {
2565 grub_free(g_img_chunk_list.chunk);
2566 }
2567
2568 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2569 {
2570 grub_file_close(file);
2571 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2572 }
2573
2574 /* get image chunk data */
2575 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2576 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2577 if (NULL == g_img_chunk_list.chunk)
2578 {
2579 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2580 }
2581
2582 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2583 g_img_chunk_list.cur_chunk = 0;
2584
2585 start = file->device->disk->partition->start;
2586
2587 ventoy_get_block_list(file, &g_img_chunk_list, start);
2588
2589 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2590 grub_file_close(file);
2591
2592 if (rc)
2593 {
2594 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2595 }
2596
2597 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2598 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2599 }
2600
2601 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2602 {
2603 grub_uint64_t offset = 0;
2604 grub_uint32_t align = 0;
2605 grub_file_t file = NULL;
2606 conf_replace *node = NULL;
2607
2608 (void)ctxt;
2609 (void)argc;
2610 (void)args;
2611
2612 debug("select conf replace argc:%d\n", argc);
2613
2614 if (argc < 2)
2615 {
2616 return 0;
2617 }
2618
2619 node = ventoy_plugin_find_conf_replace(args[1]);
2620 if (!node)
2621 {
2622 debug("Conf replace not found for %s\n", args[1]);
2623 goto end;
2624 }
2625
2626 debug("Find conf replace for %s\n", args[1]);
2627
2628 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2629 if (!file)
2630 {
2631 debug("<(loop)%s> NOT exist\n", node->orgconf);
2632 goto end;
2633 }
2634
2635 offset = grub_iso9660_get_last_file_dirent_pos(file);
2636 grub_file_close(file);
2637
2638 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2639 if (!file)
2640 {
2641 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2642 goto end;
2643 }
2644
2645 align = ((int)file->size + 2047) / 2048 * 2048;
2646
2647 if (align > vtoy_max_replace_file_size)
2648 {
2649 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2650 goto end;
2651 }
2652
2653 grub_file_read(file, g_conf_replace_new_buf, file->size);
2654 g_conf_replace_new_len = (int)file->size;
2655 g_conf_replace_new_len_align = align;
2656
2657 g_conf_replace_node = node;
2658 g_conf_replace_offset = offset + 2;
2659
2660 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2661
2662 end:
2663 if (file)
2664 {
2665 grub_file_close(file);
2666 }
2667 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2668 }
2669
2670 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2671 {
2672 int i = 0;
2673 int pos = 0;
2674 char *buf = NULL;
2675 char configfile[128];
2676 install_template *node = NULL;
2677
2678 (void)ctxt;
2679 (void)argc;
2680 (void)args;
2681
2682 debug("select auto installation argc:%d\n", argc);
2683
2684 if (argc < 1)
2685 {
2686 return 0;
2687 }
2688
2689 node = ventoy_plugin_find_install_template(args[0]);
2690 if (!node)
2691 {
2692 debug("Auto install template not found for %s\n", args[0]);
2693 return 0;
2694 }
2695
2696 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2697 {
2698 node->cursel = node->autosel - 1;
2699 debug("Auto install template auto select %d\n", node->autosel);
2700 return 0;
2701 }
2702
2703 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2704 if (!buf)
2705 {
2706 return 0;
2707 }
2708
2709 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2710 " echo %s\n}\n", "123");
2711
2712 for (i = 0; i < node->templatenum; i++)
2713 {
2714 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2715 " echo 123\n}\n",
2716 node->templatepath[i].path);
2717 }
2718
2719 g_ventoy_menu_esc = 1;
2720 g_ventoy_suppress_esc = 1;
2721
2722 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2723 grub_script_execute_sourcecode(configfile);
2724
2725 g_ventoy_menu_esc = 0;
2726 g_ventoy_suppress_esc = 0;
2727
2728 grub_free(buf);
2729
2730 node->cursel = g_ventoy_last_entry - 1;
2731
2732 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2733 }
2734
2735 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2736 {
2737 int i = 0;
2738 int pos = 0;
2739 char *buf = NULL;
2740 char configfile[128];
2741 persistence_config *node;
2742
2743 (void)ctxt;
2744 (void)argc;
2745 (void)args;
2746
2747 debug("select persistence argc:%d\n", argc);
2748
2749 if (argc < 1)
2750 {
2751 return 0;
2752 }
2753
2754 node = ventoy_plugin_find_persistent(args[0]);
2755 if (!node)
2756 {
2757 debug("Persistence image not found for %s\n", args[0]);
2758 return 0;
2759 }
2760
2761 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2762 {
2763 node->cursel = node->autosel - 1;
2764 debug("Persistence image auto select %d\n", node->autosel);
2765 return 0;
2766 }
2767
2768 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2769 if (!buf)
2770 {
2771 return 0;
2772 }
2773
2774 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2775 " echo %s\n}\n", "123");
2776
2777 for (i = 0; i < node->backendnum; i++)
2778 {
2779 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2780 " echo 123\n}\n",
2781 node->backendpath[i].path);
2782
2783 }
2784
2785 g_ventoy_menu_esc = 1;
2786 g_ventoy_suppress_esc = 1;
2787
2788 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2789 grub_script_execute_sourcecode(configfile);
2790
2791 g_ventoy_menu_esc = 0;
2792 g_ventoy_suppress_esc = 0;
2793
2794 grub_free(buf);
2795
2796 node->cursel = g_ventoy_last_entry - 1;
2797
2798 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2799 }
2800
2801 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2802 {
2803 grub_uint32_t i;
2804 ventoy_img_chunk *cur;
2805
2806 (void)ctxt;
2807 (void)argc;
2808 (void)args;
2809
2810 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2811 {
2812 cur = g_img_chunk_list.chunk + i;
2813 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2814 cur->img_start_sector, cur->img_end_sector,
2815 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2816 );
2817 }
2818
2819 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2820 }
2821
2822 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2823 {
2824 grub_uint32_t i;
2825 grub_file_t file;
2826 ventoy_img_chunk_list chunklist;
2827
2828 (void)ctxt;
2829 (void)argc;
2830
2831 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2832 if (!file)
2833 {
2834 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2835 }
2836
2837 /* get image chunk data */
2838 grub_memset(&chunklist, 0, sizeof(chunklist));
2839 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2840 if (NULL == chunklist.chunk)
2841 {
2842 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2843 }
2844
2845 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2846 chunklist.cur_chunk = 0;
2847
2848 ventoy_get_block_list(file, &chunklist, 0);
2849
2850 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2851 {
2852 grub_printf("########## UNSUPPORTED ###############\n");
2853 }
2854
2855 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2856
2857 for (i = 0; i < chunklist.cur_chunk; i++)
2858 {
2859 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2860 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2861 }
2862
2863 grub_printf("\n==================================\n");
2864
2865 for (i = 0; i < chunklist.cur_chunk; i++)
2866 {
2867 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2868 (ulonglong)chunklist.chunk[i].img_start_sector,
2869 (ulonglong)chunklist.chunk[i].img_end_sector,
2870 (ulonglong)chunklist.chunk[i].disk_start_sector,
2871 (ulonglong)chunklist.chunk[i].disk_end_sector
2872 );
2873 }
2874
2875 grub_free(chunklist.chunk);
2876 grub_file_close(file);
2877
2878 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2879 }
2880
2881 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2882 {
2883 int i;
2884 ventoy_grub_param_file_replace *replace = NULL;
2885
2886 (void)ctxt;
2887 (void)argc;
2888 (void)args;
2889
2890 if (argc >= 2)
2891 {
2892 replace = &(g_grub_param->file_replace);
2893 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2894
2895 replace->old_name_cnt = 0;
2896 for (i = 0; i < 4 && i + 1 < argc; i++)
2897 {
2898 replace->old_name_cnt++;
2899 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2900 }
2901
2902 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2903 }
2904
2905 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2906 }
2907
2908 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2909 {
2910 (void)ctxt;
2911 (void)argc;
2912 (void)args;
2913
2914 if (argc == 0)
2915 {
2916 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2917 grub_printf("%s", g_list_script_buf);
2918 }
2919 else
2920 {
2921 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2922 grub_printf("%s", g_tree_script_buf);
2923 }
2924
2925 return 0;
2926 }
2927
2928 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2929 {
2930 img_info *cur = g_ventoy_img_list;
2931
2932 (void)ctxt;
2933 (void)argc;
2934 (void)args;
2935
2936 while (cur)
2937 {
2938 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2939 grub_printf("name:<%s>\n\n", cur->name);
2940 cur = cur->next;
2941 }
2942
2943 return 0;
2944 }
2945
2946 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2947 {
2948 (void)ctxt;
2949 (void)argc;
2950 (void)args;
2951
2952 ventoy_plugin_dump_injection();
2953
2954 return 0;
2955 }
2956
2957 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2958 {
2959 (void)ctxt;
2960 (void)argc;
2961 (void)args;
2962
2963 ventoy_plugin_dump_auto_install();
2964
2965 return 0;
2966 }
2967
2968 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2969 {
2970 (void)ctxt;
2971 (void)argc;
2972 (void)args;
2973
2974 ventoy_plugin_dump_persistence();
2975
2976 return 0;
2977 }
2978
2979 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2980 {
2981 (void)ctxt;
2982 (void)argc;
2983 (void)args;
2984
2985 if (argc != 1)
2986 {
2987 return 1;
2988 }
2989
2990 if (args[0][0] == '0')
2991 {
2992 return g_ventoy_memdisk_mode ? 0 : 1;
2993 }
2994 else if (args[0][0] == '1')
2995 {
2996 return g_ventoy_iso_raw ? 0 : 1;
2997 }
2998 else if (args[0][0] == '2')
2999 {
3000 return g_ventoy_iso_uefi_drv ? 0 : 1;
3001 }
3002
3003 return 1;
3004 }
3005
3006 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3007 {
3008 static int configfile_mode = 0;
3009 char memfile[128] = {0};
3010
3011 (void)ctxt;
3012 (void)argc;
3013 (void)args;
3014
3015 /*
3016 * args[0]: 0:normal 1:configfile
3017 * args[1]: 0:list_buf 1:tree_buf
3018 */
3019
3020 if (argc != 2)
3021 {
3022 debug("Invalid argc %d\n", argc);
3023 return 0;
3024 }
3025
3026 if (args[0][0] == '0')
3027 {
3028 if (args[1][0] == '0')
3029 {
3030 grub_script_execute_sourcecode(g_list_script_buf);
3031 }
3032 else
3033 {
3034 grub_script_execute_sourcecode(g_tree_script_buf);
3035 }
3036 }
3037 else
3038 {
3039 if (configfile_mode)
3040 {
3041 debug("Now already in F3 mode %d\n", configfile_mode);
3042 return 0;
3043 }
3044
3045 if (args[1][0] == '0')
3046 {
3047 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3048 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3049 }
3050 else
3051 {
3052 g_ventoy_last_entry = -1;
3053 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3054 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3055 }
3056
3057 configfile_mode = 1;
3058 grub_script_execute_sourcecode(memfile);
3059 configfile_mode = 0;
3060 }
3061
3062 return 0;
3063 }
3064
3065 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3066 {
3067 grub_file_t file;
3068
3069 (void)ctxt;
3070
3071 if (argc != 1)
3072 {
3073 return 1;
3074 }
3075
3076 g_ventoy_case_insensitive = 1;
3077 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3078 g_ventoy_case_insensitive = 0;
3079
3080 grub_errno = 0;
3081
3082 if (file)
3083 {
3084 grub_file_close(file);
3085 return 0;
3086 }
3087 return 1;
3088 }
3089
3090 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3091 {
3092 int id = 0;
3093 int find = 0;
3094 grub_disk_t disk;
3095 const char *isopath = NULL;
3096 char hdname[32];
3097 ventoy_mbr_head mbr;
3098
3099 (void)ctxt;
3100 (void)argc;
3101
3102 if (argc != 1)
3103 {
3104 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3105 }
3106
3107 isopath = grub_env_get("vtoy_iso_part");
3108 if (!isopath)
3109 {
3110 debug("isopath is null %p\n", isopath);
3111 return 0;
3112 }
3113
3114 debug("isopath is %s\n", isopath);
3115
3116 for (id = 0; id < 30 && (find == 0); id++)
3117 {
3118 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3119 if (grub_strstr(isopath, hdname))
3120 {
3121 debug("skip %s ...\n", hdname);
3122 continue;
3123 }
3124
3125 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3126
3127 disk = grub_disk_open(hdname);
3128 if (!disk)
3129 {
3130 debug("%s not exist\n", hdname);
3131 break;
3132 }
3133
3134 grub_memset(&mbr, 0, sizeof(mbr));
3135 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3136 {
3137 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3138 {
3139 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3140 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3141 {
3142
3143 grub_env_set(args[0], hdname);
3144 find = 1;
3145 }
3146 }
3147 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3148 }
3149 else
3150 {
3151 debug("read %s failed\n", hdname);
3152 }
3153
3154 grub_disk_close(disk);
3155 }
3156
3157 return 0;
3158 }
3159
3160 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3161 {
3162 int len = 1024;
3163 grub_file_t file;
3164 char *buf = NULL;
3165
3166 (void)ctxt;
3167 (void)argc;
3168
3169 if (argc != 2)
3170 {
3171 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3172 }
3173
3174 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3175 if (!file)
3176 {
3177 debug("failed to open file %s\n", args[0]);
3178 return 0;
3179 }
3180
3181 buf = grub_malloc(len);
3182 if (!buf)
3183 {
3184 goto end;
3185 }
3186
3187 buf[len - 1] = 0;
3188 grub_file_read(file, buf, len - 1);
3189
3190 ventoy_get_line(buf);
3191 ventoy_set_env(args[1], buf);
3192
3193 end:
3194
3195 grub_check_free(buf);
3196 grub_file_close(file);
3197
3198 return 0;
3199 }
3200
3201 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3202 {
3203 (void)disk;
3204 (void)data;
3205
3206 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3207 "0 %llu linear /dev/ventoy %llu\n",
3208 (ulonglong)partition->len, (ulonglong)partition->start);
3209
3210 return 0;
3211 }
3212
3213 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3214 {
3215 char *device_name = NULL;
3216 grub_device_t dev = NULL;
3217 char buf[64];
3218
3219 (void)ctxt;
3220
3221 g_part_list_pos = 0;
3222 grub_env_unset("vtoy_img_part_file");
3223
3224 if (argc != 1)
3225 {
3226 return 1;
3227 }
3228
3229 device_name = grub_file_get_device_name(args[0]);
3230 if (!device_name)
3231 {
3232 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3233 goto end;
3234 }
3235
3236 dev = grub_device_open(device_name);
3237 if (!dev)
3238 {
3239 debug("grub_device_open failed, %s\n", device_name);
3240 goto end;
3241 }
3242
3243 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3244
3245 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3246 grub_env_set("vtoy_img_part_file", buf);
3247
3248 end:
3249
3250 check_free(device_name, grub_free);
3251 check_free(dev, grub_device_close);
3252
3253 return 0;
3254 }
3255
3256
3257 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3258 {
3259 int rc = 1;
3260 grub_file_t file;
3261 char *buf = NULL;
3262
3263 (void)ctxt;
3264 (void)argc;
3265
3266 if (argc != 2)
3267 {
3268 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3269 }
3270
3271 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3272 if (!file)
3273 {
3274 debug("failed to open file %s\n", args[0]);
3275 return 1;
3276 }
3277
3278 buf = grub_malloc(file->size + 1);
3279 if (!buf)
3280 {
3281 goto end;
3282 }
3283
3284 buf[file->size] = 0;
3285 grub_file_read(file, buf, file->size);
3286
3287 if (grub_strstr(buf, args[1]))
3288 {
3289 rc = 0;
3290 }
3291
3292 end:
3293
3294 grub_check_free(buf);
3295 grub_file_close(file);
3296
3297 return rc;
3298 }
3299
3300 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3301 {
3302 int len;
3303 grub_file_t file;
3304 char buf[64];
3305 grub_uint64_t size;
3306 ventoy_iso9660_vd pvd;
3307
3308 (void)ctxt;
3309 (void)argc;
3310
3311 if (argc != 4)
3312 {
3313 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3314 }
3315
3316 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3317 if (!file)
3318 {
3319 debug("failed to open file %s\n", args[0]);
3320 return 0;
3321 }
3322
3323 grub_file_seek(file, 16 * 2048);
3324 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3325 if (len != sizeof(pvd))
3326 {
3327 debug("failed to read pvd %d\n", len);
3328 goto end;
3329 }
3330
3331 grub_memset(buf, 0, sizeof(buf));
3332 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3333 ventoy_set_env(args[1], buf);
3334
3335 grub_memset(buf, 0, sizeof(buf));
3336 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3337 ventoy_set_env(args[2], buf);
3338
3339 size = pvd.space;
3340 size *= 2048;
3341 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3342 ventoy_set_env(args[3], buf);
3343
3344 end:
3345 grub_file_close(file);
3346
3347 return 0;
3348 }
3349
3350 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3351 {
3352 int len;
3353 grub_file_t file;
3354 char buf[64];
3355
3356 (void)ctxt;
3357 (void)argc;
3358
3359 if (argc != 2)
3360 {
3361 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3362 }
3363
3364 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3365 if (!file)
3366 {
3367 debug("failed to open file %s\n", args[0]);
3368 return 0;
3369 }
3370
3371 grub_memset(buf, 0, sizeof(buf));
3372 grub_file_seek(file, 16 * 2048 + 813);
3373 len = (int)grub_file_read(file, buf, 17);
3374 if (len != 17)
3375 {
3376 debug("failed to read create date %d\n", len);
3377 goto end;
3378 }
3379
3380 ventoy_set_env(args[1], buf);
3381
3382 end:
3383 grub_file_close(file);
3384
3385 return 0;
3386 }
3387
3388 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3389 {
3390 (void)ctxt;
3391 (void)argc;
3392 (void)args;
3393
3394 ventoy_env_hook_root(1);
3395
3396 return 0;
3397 }
3398
3399 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3400 {
3401 (void)ctxt;
3402 (void)argc;
3403 (void)args;
3404
3405 ventoy_env_hook_root(0);
3406
3407 return 0;
3408 }
3409
3410 #ifdef GRUB_MACHINE_EFI
3411 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3412 {
3413 int ret = 1;
3414 grub_uint8_t *var;
3415 grub_size_t size;
3416 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3417
3418 (void)ctxt;
3419 (void)argc;
3420 (void)args;
3421
3422 var = grub_efi_get_variable("SecureBoot", &global, &size);
3423 if (var && *var == 1)
3424 {
3425 return 0;
3426 }
3427
3428 return ret;
3429 }
3430 #else
3431 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3432 {
3433 (void)ctxt;
3434 (void)argc;
3435 (void)args;
3436 return 1;
3437 }
3438 #endif
3439
3440 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3441 {
3442 int i;
3443 int buflen;
3444 int datalen;
3445 int loclen;
3446 int img_chunk_num;
3447 int image_sector_size;
3448 char cmd[64];
3449 ventoy_chain_head *chain;
3450 ventoy_img_chunk *chunk;
3451 ventoy_os_param *osparam;
3452 ventoy_image_location *location;
3453 ventoy_image_disk_region *region;
3454 struct grub_acpi_table_header *acpi;
3455
3456 (void)ctxt;
3457
3458 if (argc != 2)
3459 {
3460 return 1;
3461 }
3462
3463 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3464
3465 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3466 if (!chain)
3467 {
3468 return 1;
3469 }
3470
3471 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3472
3473 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3474 {
3475 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3476 return 1;
3477 }
3478
3479 img_chunk_num = chain->img_chunk_num;
3480
3481 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3482 datalen = sizeof(ventoy_os_param) + loclen;
3483
3484 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3485 acpi = grub_zalloc(buflen);
3486 if (!acpi)
3487 {
3488 return 1;
3489 }
3490
3491 /* Step1: Fill acpi table header */
3492 grub_memcpy(acpi->signature, "VTOY", 4);
3493 acpi->length = buflen;
3494 acpi->revision = 1;
3495 grub_memcpy(acpi->oemid, "VENTOY", 6);
3496 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3497 acpi->oemrev = 1;
3498 acpi->creator_id[0] = 1;
3499 acpi->creator_rev = 1;
3500
3501 /* Step2: Fill data */
3502 osparam = (ventoy_os_param *)(acpi + 1);
3503 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3504 osparam->vtoy_img_location_addr = 0;
3505 osparam->vtoy_img_location_len = loclen;
3506 osparam->chksum = 0;
3507 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3508
3509 location = (ventoy_image_location *)(osparam + 1);
3510 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3511 location->image_sector_size = image_sector_size;
3512 location->disk_sector_size = chain->disk_sector_size;
3513 location->region_count = img_chunk_num;
3514
3515 region = location->regions;
3516 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3517 if (512 == image_sector_size)
3518 {
3519 for (i = 0; i < img_chunk_num; i++)
3520 {
3521 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3522 region->image_start_sector = chunk->img_start_sector * 4;
3523 region->disk_start_sector = chunk->disk_start_sector;
3524 region++;
3525 chunk++;
3526 }
3527 }
3528 else
3529 {
3530 for (i = 0; i < img_chunk_num; i++)
3531 {
3532 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3533 region->image_start_sector = chunk->img_start_sector;
3534 region->disk_start_sector = chunk->disk_start_sector;
3535 region++;
3536 chunk++;
3537 }
3538 }
3539
3540 /* Step3: Fill acpi checksum */
3541 acpi->checksum = 0;
3542 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3543
3544 /* load acpi table */
3545 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3546 grub_script_execute_sourcecode(cmd);
3547
3548 grub_free(acpi);
3549
3550 VENTOY_CMD_RETURN(0);
3551 }
3552
3553 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3554 {
3555 (void)ctxt;
3556 (void)argc;
3557 (void)args;
3558
3559 g_ventoy_last_entry_back = g_ventoy_last_entry;
3560 g_ventoy_last_entry = -1;
3561
3562 return 0;
3563 }
3564
3565 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3566 {
3567 (void)ctxt;
3568 (void)argc;
3569 (void)args;
3570
3571 g_ventoy_last_entry = g_ventoy_last_entry_back;
3572
3573 return 0;
3574 }
3575
3576 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3577 {
3578 grub_uint64_t sectors;
3579
3580 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3581 {
3582 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3583 }
3584 else
3585 {
3586 sectors = gpt->MBR.PartTbl[0].SectorCount;
3587 }
3588
3589 return sectors * 512;
3590 }
3591
3592 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3593 {
3594 const char *pos = filename + 1;
3595
3596 if (info->dir)
3597 {
3598 while (*pos)
3599 {
3600 if (*pos == '.')
3601 {
3602 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3603 {
3604 grub_strncpy((char *)data, filename, 128);
3605 return 1;
3606 }
3607 }
3608 pos++;
3609 }
3610 }
3611
3612 return 0;
3613 }
3614
3615 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3616 {
3617 int rc = 1;
3618 char *device_name = NULL;
3619 grub_device_t dev = NULL;
3620 grub_fs_t fs = NULL;
3621 char buf[128] = {0};
3622
3623 (void)ctxt;
3624
3625 if (argc != 3)
3626 {
3627 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3628 return 1;
3629 }
3630
3631 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3632
3633 device_name = grub_file_get_device_name(args[0]);
3634 if (!device_name)
3635 {
3636 debug("grub_file_get_device_name failed, %s\n", args[0]);
3637 goto end;
3638 }
3639
3640 dev = grub_device_open(device_name);
3641 if (!dev)
3642 {
3643 debug("grub_device_open failed, %s\n", device_name);
3644 goto end;
3645 }
3646
3647 fs = grub_fs_probe(dev);
3648 if (!fs)
3649 {
3650 debug("grub_fs_probe failed, %s\n", device_name);
3651 goto end;
3652 }
3653
3654 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3655
3656 if (buf[0])
3657 {
3658 ventoy_set_env(args[2], buf);
3659 }
3660
3661 rc = 0;
3662
3663 end:
3664
3665 check_free(device_name, grub_free);
3666 check_free(dev, grub_device_close);
3667
3668 return rc;
3669 }
3670
3671 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3672 {
3673 char name[64];
3674 int ret;
3675 grub_disk_t disk;
3676 grub_device_t dev;
3677
3678 (void)argc;
3679 (void)ctxt;
3680
3681 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3682 if (!g_ventoy_part_info)
3683 {
3684 return 1;
3685 }
3686
3687 disk = grub_disk_open(args[0]);
3688 if (!disk)
3689 {
3690 debug("Failed to open disk %s\n", args[0]);
3691 return 1;
3692 }
3693
3694 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3695
3696 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3697 grub_disk_close(disk);
3698
3699 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3700 dev = grub_device_open(name);
3701 if (dev)
3702 {
3703 /* make sure that we are running in a correct Ventoy device */
3704 ret = ventoy_check_device(dev);
3705 grub_device_close(dev);
3706
3707 if (ret)
3708 {
3709 grub_exit();
3710 }
3711 }
3712
3713 return 0;
3714 }
3715
3716 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
3717 {
3718 int ret = 1;
3719 const char *vcfg = NULL;
3720
3721 (void)argc;
3722 (void)ctxt;
3723
3724 vcfg = ventoy_plugin_get_custom_boot(args[0]);
3725 if (vcfg)
3726 {
3727 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
3728 grub_env_set(args[1], vcfg);
3729 ret = 0;
3730 }
3731 else
3732 {
3733 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
3734 }
3735
3736 grub_errno = 0;
3737 return ret;
3738 }
3739
3740
3741 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3742 {
3743 int id;
3744 grub_uint8_t zeroguid[16] = {0};
3745
3746 (void)argc;
3747 (void)ctxt;
3748
3749 id = (int)grub_strtoul(args[0], NULL, 10);
3750 grub_errno = 0;
3751
3752 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3753 {
3754 if (id >= 1 && id <= 128)
3755 {
3756 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3757 {
3758 return 0;
3759 }
3760 }
3761 }
3762 else
3763 {
3764 if (id >= 1 && id <= 4)
3765 {
3766 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3767 {
3768 return 0;
3769 }
3770 }
3771 }
3772
3773 return 1;
3774 }
3775
3776 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3777 {
3778 int rc = 1;
3779 char *device_name = NULL;
3780 grub_device_t dev = NULL;
3781 grub_fs_t fs = NULL;
3782 char *label = NULL;
3783
3784 (void)ctxt;
3785
3786 if (argc != 2)
3787 {
3788 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3789 return 1;
3790 }
3791
3792 device_name = grub_file_get_device_name(args[0]);
3793 if (!device_name)
3794 {
3795 debug("grub_file_get_device_name failed, %s\n", args[0]);
3796 goto end;
3797 }
3798
3799 dev = grub_device_open(device_name);
3800 if (!dev)
3801 {
3802 debug("grub_device_open failed, %s\n", device_name);
3803 goto end;
3804 }
3805
3806 fs = grub_fs_probe(dev);
3807 if (!fs)
3808 {
3809 debug("grub_fs_probe failed, %s\n", device_name);
3810 goto end;
3811 }
3812
3813 fs->fs_label(dev, &label);
3814 if (label)
3815 {
3816 ventoy_set_env(args[1], label);
3817 grub_free(label);
3818 }
3819
3820 rc = 0;
3821
3822 end:
3823
3824 check_free(device_name, grub_free);
3825 check_free(dev, grub_device_close);
3826
3827 return rc;
3828 }
3829
3830 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3831 {
3832 if (!info->dir)
3833 {
3834 grub_snprintf((char *)data, 256, "%s", filename);
3835 return 1;
3836 }
3837
3838 return 0;
3839 }
3840
3841
3842 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3843 {
3844 int rc = 1;
3845 char *device_name = NULL;
3846 grub_device_t dev = NULL;
3847 grub_fs_t fs = NULL;
3848 char name[256] ={0};
3849
3850 (void)ctxt;
3851
3852 if (argc != 3)
3853 {
3854 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3855 return 1;
3856 }
3857
3858 device_name = grub_file_get_device_name(args[0]);
3859 if (!device_name)
3860 {
3861 debug("grub_file_get_device_name failed, %s\n", args[0]);
3862 goto end;
3863 }
3864
3865 dev = grub_device_open(device_name);
3866 if (!dev)
3867 {
3868 debug("grub_device_open failed, %s\n", device_name);
3869 goto end;
3870 }
3871
3872 fs = grub_fs_probe(dev);
3873 if (!fs)
3874 {
3875 debug("grub_fs_probe failed, %s\n", device_name);
3876 goto end;
3877 }
3878
3879 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3880 if (name[0])
3881 {
3882 ventoy_set_env(args[2], name);
3883 }
3884
3885 rc = 0;
3886
3887 end:
3888
3889 check_free(device_name, grub_free);
3890 check_free(dev, grub_device_close);
3891
3892 return rc;
3893 }
3894
3895 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3896 {
3897 char c;
3898 char *pos = NULL;
3899 char *end = NULL;
3900
3901 (void)ctxt;
3902
3903 if (argc != 2)
3904 {
3905 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3906 return 1;
3907 }
3908
3909 for (pos = args[0]; *pos; pos++)
3910 {
3911 if (*pos == '.')
3912 {
3913 end = pos;
3914 }
3915 }
3916
3917 if (end)
3918 {
3919 c = *end;
3920 *end = 0;
3921 }
3922
3923 grub_env_set(args[1], args[0]);
3924
3925 if (end)
3926 {
3927 *end = c;
3928 }
3929
3930 return 0;
3931 }
3932
3933 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
3934 {
3935 int i;
3936 int len;
3937 const char *buf;
3938
3939 (void)ctxt;
3940
3941 if (argc != 2)
3942 {
3943 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
3944 return 1;
3945 }
3946
3947 buf = args[0];
3948 len = (int)grub_strlen(buf);
3949 for (i = len; i > 0; i--)
3950 {
3951 if (buf[i - 1] == '/')
3952 {
3953 grub_env_set(args[1], buf + i);
3954 return 0;
3955 }
3956 }
3957
3958 grub_env_set(args[1], buf);
3959
3960 return 0;
3961 }
3962
3963 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3964 {
3965 struct grub_video_mode_info info;
3966 char buf[32];
3967
3968 (void)ctxt;
3969 (void)argc;
3970 (void)args;
3971
3972 if (!g_video_mode_list)
3973 {
3974 ventoy_enum_video_mode();
3975 }
3976
3977 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3978 {
3979 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3980 }
3981 else
3982 {
3983 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3984 }
3985
3986 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3987
3988 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3989 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3990
3991 VENTOY_CMD_RETURN(0);
3992 }
3993
3994 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3995 {
3996 struct grub_video_mode_info info;
3997 char buf[32];
3998
3999 (void)ctxt;
4000 (void)argc;
4001 (void)args;
4002
4003 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4004 {
4005 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4006 }
4007 else
4008 {
4009 grub_snprintf(buf, sizeof(buf), "0x0x0");
4010 }
4011
4012 grub_env_set(args[0], buf);
4013
4014 VENTOY_CMD_RETURN(0);
4015 }
4016
4017 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4018 {
4019 int id;
4020 char buf[32];
4021
4022 (void)ctxt;
4023 (void)argc;
4024
4025 if (!g_video_mode_list)
4026 {
4027 return 0;
4028 }
4029
4030 id = (int)grub_strtoul(args[0], NULL, 10);
4031 if (id < g_video_mode_num)
4032 {
4033 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4034 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4035 }
4036
4037 grub_env_set(args[1], buf);
4038
4039 VENTOY_CMD_RETURN(0);
4040 }
4041
4042 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
4043 {
4044 grub_uint64_t size = 0;
4045 grub_file_t file;
4046 va_list ap;
4047 char fullpath[256] = {0};
4048
4049 va_start (ap, fmt);
4050 grub_vsnprintf(fullpath, 255, fmt, ap);
4051 va_end (ap);
4052
4053 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
4054 if (!file)
4055 {
4056 debug("grub_file_open failed <%s>\n", fullpath);
4057 grub_errno = 0;
4058 return 0;
4059 }
4060
4061 size = file->size;
4062 grub_file_close(file);
4063 return size;
4064 }
4065
4066 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
4067 {
4068 va_list ap;
4069 grub_file_t file;
4070 char fullpath[256] = {0};
4071
4072 va_start (ap, fmt);
4073 grub_vsnprintf(fullpath, 255, fmt, ap);
4074 va_end (ap);
4075
4076 file = grub_file_open(fullpath, type);
4077 if (!file)
4078 {
4079 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
4080 grub_errno = 0;
4081 }
4082
4083 return file;
4084 }
4085
4086 int ventoy_is_file_exist(const char *fmt, ...)
4087 {
4088 va_list ap;
4089 int len;
4090 char *pos = NULL;
4091 char buf[256] = {0};
4092
4093 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
4094 pos = buf + 6;
4095
4096 va_start (ap, fmt);
4097 len = grub_vsnprintf(pos, 255, fmt, ap);
4098 va_end (ap);
4099
4100 grub_strncpy(pos + len, "\" ]", 3);
4101
4102 debug("script exec %s\n", buf);
4103
4104 if (0 == grub_script_execute_sourcecode(buf))
4105 {
4106 return 1;
4107 }
4108
4109 return 0;
4110 }
4111
4112 int ventoy_is_dir_exist(const char *fmt, ...)
4113 {
4114 va_list ap;
4115 int len;
4116 char *pos = NULL;
4117 char buf[256] = {0};
4118
4119 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
4120 pos = buf + 6;
4121
4122 va_start (ap, fmt);
4123 len = grub_vsnprintf(pos, 255, fmt, ap);
4124 va_end (ap);
4125
4126 grub_strncpy(pos + len, "\" ]", 3);
4127
4128 debug("script exec %s\n", buf);
4129
4130 if (0 == grub_script_execute_sourcecode(buf))
4131 {
4132 return 1;
4133 }
4134
4135 return 0;
4136 }
4137
4138 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
4139 {
4140 mz_stream s;
4141 grub_uint8_t *outbuf;
4142 grub_uint8_t gzHdr[10] =
4143 {
4144 0x1F, 0x8B, /* magic */
4145 8, /* z method */
4146 0, /* flags */
4147 0,0,0,0, /* mtime */
4148 4, /* xfl */
4149 3, /* OS */
4150 };
4151
4152 grub_memset(&s, 0, sizeof(mz_stream));
4153
4154 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
4155
4156 outbuf = (grub_uint8_t *)mem_out;
4157
4158 mem_out_len -= sizeof(gzHdr) + 8;
4159 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
4160 outbuf += sizeof(gzHdr);
4161
4162 s.avail_in = mem_in_len;
4163 s.next_in = mem_in;
4164
4165 s.avail_out = mem_out_len;
4166 s.next_out = outbuf;
4167
4168 mz_deflate(&s, MZ_FINISH);
4169
4170 mz_deflateEnd(&s);
4171
4172 outbuf += s.total_out;
4173 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4174 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4175
4176 return s.total_out + sizeof(gzHdr) + 8;
4177 }
4178
4179 static int ventoy_env_init(void)
4180 {
4181 char buf[64];
4182
4183 grub_env_set("vtdebug_flag", "");
4184
4185 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4186 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4187 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4188 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4189
4190 ventoy_filt_register(0, ventoy_wrapper_open);
4191
4192 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4193 if (g_grub_param)
4194 {
4195 g_grub_param->grub_env_get = grub_env_get;
4196 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4197 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4198 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4199 grub_env_set("env_param", buf);
4200 grub_env_set("ventoy_env_param", buf);
4201 grub_env_export("ventoy_env_param");
4202 }
4203
4204 return 0;
4205 }
4206
4207 static cmd_para ventoy_cmds[] =
4208 {
4209 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4210 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4211 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4212 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4213 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4214 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4215 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4216 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4217 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4218 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4219 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4220 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4221 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4222 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4223 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4224 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4225 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4226 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4227 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4228 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4229 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4230 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4231 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4232
4233 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4234 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4235 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4236 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4237 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4238 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4239 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4240
4241 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4242 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4243 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4244 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4245 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4246 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4247 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4248 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4249 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4250
4251
4252 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4253 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4254 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4255 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4256 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4257 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4258 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4259 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4260 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4261 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4262 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4263
4264 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4265 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4266 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4267 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4268 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4269 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4270
4271 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4272 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4273 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4274 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4275 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4276 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4277 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4278 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4279 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4280 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4281
4282 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4283 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4284 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4285 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4286 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4287 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4288 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4289 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4290
4291 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4292 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4293 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4294
4295
4296 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4297 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4298 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4299
4300 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4301 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4302 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4303
4304
4305 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4306 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4307 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4308 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4309 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4310 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4311 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4312 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4313 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4314 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4315
4316 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4317 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4318 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4319 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4320
4321 };
4322
4323
4324
4325 GRUB_MOD_INIT(ventoy)
4326 {
4327 grub_uint32_t i;
4328 cmd_para *cur = NULL;
4329
4330 ventoy_env_init();
4331
4332 ventoy_arch_mode_init();
4333
4334 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4335 {
4336 cur = ventoy_cmds + i;
4337 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4338 cur->summary, cur->description, cur->parser);
4339 }
4340 }
4341
4342 GRUB_MOD_FINI(ventoy)
4343 {
4344 grub_uint32_t i;
4345
4346 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4347 {
4348 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4349 }
4350 }
4351