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