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