]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
1. Boot menu over serial supported
[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/relocator.h>
43 #include <grub/ventoy.h>
44 #include "ventoy_def.h"
45
46 GRUB_MOD_LICENSE ("GPLv3+");
47
48 int g_ventoy_debug = 0;
49 static int g_efi_os = 0xFF;
50 initrd_info *g_initrd_img_list = NULL;
51 initrd_info *g_initrd_img_tail = NULL;
52 int g_initrd_img_count = 0;
53 int g_valid_initrd_count = 0;
54 int g_default_menu_mode = 0;
55 int g_filt_dot_underscore_file = 0;
56 static grub_file_t g_old_file;
57
58 char g_iso_path[256];
59 char g_img_swap_tmp_buf[1024];
60 img_info g_img_swap_tmp;
61 img_info *g_ventoy_img_list = NULL;
62
63 int g_ventoy_img_count = 0;
64
65 grub_device_t g_enum_dev = NULL;
66 grub_fs_t g_enum_fs = NULL;
67 img_iterator_node g_img_iterator_head;
68 img_iterator_node *g_img_iterator_tail = NULL;
69
70 grub_uint8_t g_ventoy_break_level = 0;
71 grub_uint8_t g_ventoy_debug_level = 0;
72 grub_uint8_t g_ventoy_chain_type = 0;
73
74 grub_uint8_t *g_ventoy_cpio_buf = NULL;
75 grub_uint32_t g_ventoy_cpio_size = 0;
76 cpio_newc_header *g_ventoy_initrd_head = NULL;
77 grub_uint8_t *g_ventoy_runtime_buf = NULL;
78
79 ventoy_grub_param *g_grub_param = NULL;
80
81 ventoy_guid g_ventoy_guid = VENTOY_GUID;
82
83 ventoy_img_chunk_list g_img_chunk_list;
84
85 int g_wimboot_enable = 0;
86 ventoy_img_chunk_list g_wimiso_chunk_list;
87 char *g_wimiso_path = NULL;
88
89 static char *g_tree_script_buf = NULL;
90 static int g_tree_script_pos = 0;
91
92 static char *g_list_script_buf = NULL;
93 static int g_list_script_pos = 0;
94
95 static const char *g_menu_class[] =
96 {
97 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg"
98 };
99
100 static const char *g_menu_prefix[] =
101 {
102 "iso", "wim", "efi", "img"
103 };
104
105 void ventoy_debug(const char *fmt, ...)
106 {
107 va_list args;
108
109 va_start (args, fmt);
110 grub_vprintf (fmt, args);
111 va_end (args);
112 }
113
114 int ventoy_is_efi_os(void)
115 {
116 if (g_efi_os > 1)
117 {
118 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
119 }
120
121 return g_efi_os;
122 }
123
124 static int ventoy_get_fs_type(const char *fs)
125 {
126 if (NULL == fs)
127 {
128 return ventoy_fs_max;
129 }
130 else if (grub_strncmp(fs, "exfat", 5) == 0)
131 {
132 return ventoy_fs_exfat;
133 }
134 else if (grub_strncmp(fs, "ntfs", 4) == 0)
135 {
136 return ventoy_fs_ntfs;
137 }
138 else if (grub_strncmp(fs, "ext", 3) == 0)
139 {
140 return ventoy_fs_ext;
141 }
142 else if (grub_strncmp(fs, "xfs", 3) == 0)
143 {
144 return ventoy_fs_xfs;
145 }
146 else if (grub_strncmp(fs, "udf", 3) == 0)
147 {
148 return ventoy_fs_udf;
149 }
150 else if (grub_strncmp(fs, "fat", 3) == 0)
151 {
152 return ventoy_fs_fat;
153 }
154
155 return ventoy_fs_max;
156 }
157
158 static int ventoy_string_check(const char *str, grub_char_check_func check)
159 {
160 if (!str)
161 {
162 return 0;
163 }
164
165 for ( ; *str; str++)
166 {
167 if (!check(*str))
168 {
169 return 0;
170 }
171 }
172
173 return 1;
174 }
175
176
177 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
178 {
179 grub_memcpy(buf, (char *)file->data + file->offset, len);
180 return len;
181 }
182
183 static grub_err_t ventoy_fs_close(grub_file_t file)
184 {
185 grub_file_close(g_old_file);
186 grub_free(file->data);
187
188 file->device = 0;
189 file->name = 0;
190
191 return 0;
192 }
193
194 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
195 {
196 int len;
197 grub_file_t file;
198 static struct grub_fs vtoy_fs =
199 {
200 .name = "vtoy",
201 .fs_dir = 0,
202 .fs_open = 0,
203 .fs_read = ventoy_fs_read,
204 .fs_close = ventoy_fs_close,
205 .fs_label = 0,
206 .next = 0
207 };
208
209 if (type != 52)
210 {
211 return rawFile;
212 }
213
214 file = (grub_file_t)grub_zalloc(sizeof (*file));
215 if (!file)
216 {
217 return 0;
218 }
219
220 file->data = grub_malloc(rawFile->size + 4096);
221 if (!file->data)
222 {
223 return 0;
224 }
225
226 grub_file_read(rawFile, file->data, rawFile->size);
227 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
228
229 g_old_file = rawFile;
230
231 file->size = rawFile->size + len;
232 file->device = rawFile->device;
233 file->fs = &vtoy_fs;
234 file->not_easily_seekable = 1;
235
236 return file;
237 }
238
239 static int ventoy_check_decimal_var(const char *name, long *value)
240 {
241 const char *value_str = NULL;
242
243 value_str = grub_env_get(name);
244 if (NULL == value_str)
245 {
246 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
247 }
248
249 if (!ventoy_is_decimal(value_str))
250 {
251 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
252 }
253
254 *value = grub_strtol(value_str, NULL, 10);
255
256 return GRUB_ERR_NONE;
257 }
258
259 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
260 {
261 if (argc != 1)
262 {
263 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
264 }
265
266 if (0 == grub_strcmp(args[0], "on"))
267 {
268 g_ventoy_debug = 1;
269 grub_env_set("vtdebug_flag", "debug");
270 }
271 else
272 {
273 g_ventoy_debug = 0;
274 grub_env_set("vtdebug_flag", "");
275 }
276
277 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
278 }
279
280 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
281 {
282 (void)ctxt;
283
284 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
285 {
286 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
287 grub_printf(" level:\r\n");
288 grub_printf(" 01/11: busybox / (+cat log)\r\n");
289 grub_printf(" 02/12: initrd / (+cat log)\r\n");
290 grub_printf(" 03/13: hook / (+cat log)\r\n");
291 grub_printf("\r\n");
292 grub_printf(" debug:\r\n");
293 grub_printf(" 0: debug is on\r\n");
294 grub_printf(" 1: debug is off\r\n");
295 grub_printf("\r\n");
296 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
297 }
298
299 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
300
301 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
302 {
303 g_ventoy_debug_level = 1;
304 }
305
306 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
307 }
308
309 static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
310 {
311 (void)ctxt;
312
313 if (argc != 2)
314 {
315 return 1;
316 }
317
318 return (grub_strstr(args[0], args[1])) ? 0 : 1;
319 }
320
321 static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
322 {
323 char *c0, *c1;
324
325 (void)ctxt;
326
327 if (argc != 2)
328 {
329 return 1;
330 }
331
332 c0 = args[0];
333 c1 = args[1];
334
335 while (*c0 && *c1)
336 {
337 if (*c0 != *c1)
338 {
339 return 1;
340 }
341 c0++;
342 c1++;
343 }
344
345 if (*c1)
346 {
347 return 1;
348 }
349
350 return 0;
351 }
352
353 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
354 {
355 long value_long = 0;
356 char buf[32];
357
358 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
359 {
360 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
361 }
362
363 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
364 {
365 return grub_errno;
366 }
367
368 value_long += grub_strtol(args[1], NULL, 10);
369
370 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
371 grub_env_set(args[0], buf);
372
373 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
374 }
375
376 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
377 {
378 int rc = 1;
379 char buf[32];
380 grub_file_t file;
381
382 (void)ctxt;
383 (void)argc;
384 (void)args;
385
386 if (argc != 2)
387 {
388 return rc;
389 }
390
391 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
392 if (file == NULL)
393 {
394 debug("failed to open file <%s> for udf check\n", args[0]);
395 return 1;
396 }
397
398 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
399
400 grub_env_set(args[1], buf);
401
402 grub_file_close(file);
403 rc = 0;
404
405 return rc;
406 }
407
408 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
409 {
410 grub_file_t file;
411
412 (void)ctxt;
413 (void)argc;
414 (void)args;
415
416 g_wimboot_enable = 0;
417 grub_check_free(g_wimiso_path);
418 grub_check_free(g_wimiso_chunk_list.chunk);
419
420 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
421 if (!file)
422 {
423 return 0;
424 }
425
426 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
427 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
428 if (NULL == g_wimiso_chunk_list.chunk)
429 {
430 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
431 }
432
433 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
434 g_wimiso_chunk_list.cur_chunk = 0;
435
436 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
437
438 g_wimboot_enable = 1;
439 g_wimiso_path = grub_strdup(args[0]);
440
441 grub_file_close(file);
442
443 return 0;
444 }
445
446 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
447 {
448 int len;
449 grub_file_t file;
450 char exec[128];
451 char *data = NULL;
452 grub_uint32_t offset;
453
454 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
455 if (file == NULL)
456 {
457 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
458 return 1;
459 }
460
461 len = (int)file->size;
462
463 data = (char *)grub_malloc(file->size);
464 if (!data)
465 {
466 return 1;
467 }
468
469 grub_file_read(file, data, file->size);
470 grub_file_close(file);
471
472 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
473 grub_script_execute_sourcecode(exec);
474
475 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
476 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
477 grub_file_close(file);
478
479 grub_script_execute_sourcecode("loopback -d efiboot");
480
481 *buf = data;
482 *datalen = len;
483 *direntoff = offset + 2;
484
485 return 0;
486 }
487
488 static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
489 {
490 int len = 0;
491 int totlen = 0;
492 int offset = 0;
493 grub_file_t file;
494 char name[32];
495 char value[32];
496 char *buf = NULL;
497 char *data = NULL;
498 ventoy_iso9660_override *dirent;
499
500 (void)ctxt;
501
502 if (argc != 2)
503 {
504 return 1;
505 }
506
507 totlen = sizeof(ventoy_chain_head);
508
509 if (ventoy_load_efiboot_template(&buf, &len, &offset))
510 {
511 debug("failed to load efiboot template %d\n", len);
512 return 1;
513 }
514
515 totlen += len;
516
517 debug("efiboot template len:%d offset:%d\n", len, offset);
518
519 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
520 if (file == NULL)
521 {
522 debug("failed to open file <%s>\n", args[0]);
523 return 1;
524 }
525
526 totlen += ventoy_align_2k(file->size);
527
528 dirent = (ventoy_iso9660_override *)(buf + offset);
529 dirent->first_sector = len / 2048;
530 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
531 dirent->size = (grub_uint32_t)file->size;
532 dirent->size_be = grub_swap_bytes32(dirent->size);
533
534 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
535
536 #ifdef GRUB_MACHINE_EFI
537 data = (char *)grub_efi_allocate_iso_buf(totlen);
538 #else
539 data = (char *)grub_malloc(totlen);
540 #endif
541
542 ventoy_fill_os_param(file, (ventoy_os_param *)data);
543
544 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
545 grub_check_free(buf);
546
547 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
548 grub_file_close(file);
549
550 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
551 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
552 grub_env_set(name, value);
553
554 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
555 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
556 grub_env_set(name, value);
557
558 return 0;
559 }
560
561 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
562 {
563 int rc = 1;
564 char name[32];
565 char value[32];
566 char *buf = NULL;
567 grub_file_t file;
568
569 (void)ctxt;
570 (void)argc;
571 (void)args;
572
573 if (argc != 2)
574 {
575 return rc;
576 }
577
578 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
579 if (file == NULL)
580 {
581 debug("failed to open file <%s>\n", args[0]);
582 return 1;
583 }
584
585 #ifdef GRUB_MACHINE_EFI
586 buf = (char *)grub_efi_allocate_iso_buf(file->size);
587 #else
588 buf = (char *)grub_malloc(file->size);
589 #endif
590
591 grub_file_read(file, buf, file->size);
592
593 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
594 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
595 grub_env_set(name, value);
596
597 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
598 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
599 grub_env_set(name, value);
600
601 grub_file_close(file);
602 rc = 0;
603
604 return rc;
605 }
606
607 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
608 {
609 int rc = 1;
610 int headlen;
611 char name[32];
612 char value[32];
613 char *buf = NULL;
614 grub_file_t file;
615
616 (void)ctxt;
617 (void)argc;
618 (void)args;
619
620 if (argc != 2)
621 {
622 return rc;
623 }
624
625 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
626 if (file == NULL)
627 {
628 debug("failed to open file <%s> for udf check\n", args[0]);
629 return 1;
630 }
631
632 headlen = sizeof(ventoy_chain_head);
633
634 #ifdef GRUB_MACHINE_EFI
635 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
636 #else
637 buf = (char *)grub_malloc(headlen + file->size);
638 #endif
639
640 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
641
642 grub_file_read(file, buf + headlen, file->size);
643
644 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
645 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
646 grub_env_set(name, value);
647
648 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
649 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
650 grub_env_set(name, value);
651
652 grub_file_close(file);
653 rc = 0;
654
655 return rc;
656 }
657
658 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
659 {
660 (void)ctxt;
661
662 if (argc != 1)
663 {
664 return 1;
665 }
666
667 if (args[0][0] == '1')
668 {
669 grub_iso9660_set_nojoliet(1);
670 }
671 else
672 {
673 grub_iso9660_set_nojoliet(0);
674 }
675
676 return 0;
677 }
678
679 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
680 {
681 int i;
682 int rc = 1;
683 grub_file_t file;
684 grub_uint8_t buf[32];
685
686 (void)ctxt;
687 (void)argc;
688 (void)args;
689
690 if (argc != 1)
691 {
692 return rc;
693 }
694
695 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
696 if (file == NULL)
697 {
698 debug("failed to open file <%s> for udf check\n", args[0]);
699 return 1;
700 }
701
702 for (i = 16; i < 32; i++)
703 {
704 grub_file_seek(file, i * 2048);
705 grub_file_read(file, buf, sizeof(buf));
706 if (buf[0] == 255)
707 {
708 break;
709 }
710 }
711
712 i++;
713 grub_file_seek(file, i * 2048);
714 grub_file_read(file, buf, sizeof(buf));
715
716 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
717 {
718 i++;
719 grub_file_seek(file, i * 2048);
720 grub_file_read(file, buf, sizeof(buf));
721
722 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
723 grub_memcmp(buf + 1, "NSR03", 5) == 0)
724 {
725 rc = 0;
726 }
727 }
728
729 grub_file_close(file);
730
731 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
732
733 return rc;
734 }
735
736 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
737 {
738 long value_long1 = 0;
739 long value_long2 = 0;
740
741 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
742 {
743 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
744 }
745
746 value_long1 = grub_strtol(args[0], NULL, 10);
747 value_long2 = grub_strtol(args[2], NULL, 10);
748
749 if (0 == grub_strcmp(args[1], "eq"))
750 {
751 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
752 }
753 else if (0 == grub_strcmp(args[1], "ne"))
754 {
755 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
756 }
757 else if (0 == grub_strcmp(args[1], "gt"))
758 {
759 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
760 }
761 else if (0 == grub_strcmp(args[1], "lt"))
762 {
763 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
764 }
765 else if (0 == grub_strcmp(args[1], "ge"))
766 {
767 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
768 }
769 else if (0 == grub_strcmp(args[1], "le"))
770 {
771 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
772 }
773 else
774 {
775 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
776 }
777
778 return grub_errno;
779 }
780
781 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
782 {
783 char *pos = NULL;
784 char buf[128] = {0};
785
786 if (argc != 2)
787 {
788 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
789 }
790
791 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
792 pos = grub_strstr(buf, ",");
793 if (pos)
794 {
795 *pos = 0;
796 }
797
798 grub_env_set(args[1], buf);
799
800 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
801 }
802
803 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
804 {
805 int i;
806 char buf[256];
807 grub_disk_t disk;
808 char *pos = NULL;
809 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
810
811 (void)ctxt;
812
813 if (argc != 1)
814 {
815 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
816 }
817
818 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
819 {
820 grub_snprintf(buf, sizeof(buf) - 1, "[ -e %s/%s ]", args[0], files[i]);
821 if (0 == grub_script_execute_sourcecode(buf))
822 {
823 debug("file %s exist, ventoy_compatible YES\n", buf);
824 grub_env_set("ventoy_compatible", "YES");
825 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
826 }
827 else
828 {
829 debug("file %s NOT exist\n", buf);
830 }
831 }
832
833 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
834 pos = grub_strstr(buf, ")");
835 if (pos)
836 {
837 *pos = 0;
838 }
839
840 disk = grub_disk_open(buf);
841 if (disk)
842 {
843 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
844 grub_disk_close(disk);
845
846 g_img_swap_tmp_buf[703] = 0;
847 for (i = 319; i < 703; i++)
848 {
849 if (g_img_swap_tmp_buf[i] == 'V' &&
850 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
851 {
852 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
853 grub_env_set("ventoy_compatible", "YES");
854 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
855 }
856 }
857 }
858 else
859 {
860 debug("failed to open disk <%s>\n", buf);
861 }
862
863 grub_env_set("ventoy_compatible", "NO");
864 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
865 }
866
867 int ventoy_cmp_img(img_info *img1, img_info *img2)
868 {
869 char *s1, *s2;
870 int c1 = 0;
871 int c2 = 0;
872
873 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
874 {
875 c1 = *s1;
876 c2 = *s2;
877
878 if (grub_islower(c1))
879 {
880 c1 = c1 - 'a' + 'A';
881 }
882
883 if (grub_islower(c2))
884 {
885 c2 = c2 - 'a' + 'A';
886 }
887
888 if (c1 != c2)
889 {
890 break;
891 }
892 }
893
894 return (c1 - c2);
895 }
896
897 void ventoy_swap_img(img_info *img1, img_info *img2)
898 {
899 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
900
901 grub_memcpy(img1, img2, sizeof(img_info));
902 img1->next = g_img_swap_tmp.next;
903 img1->prev = g_img_swap_tmp.prev;
904
905 g_img_swap_tmp.next = img2->next;
906 g_img_swap_tmp.prev = img2->prev;
907 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
908 }
909
910 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
911 {
912 grub_size_t i;
913
914 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
915 {
916 return 0;
917 }
918
919 for (i = 0; i < namelen; i++)
920 {
921 if (filename[i] == ' ' || filename[i] == '\t')
922 {
923 return 0;
924 }
925
926 if ((grub_uint8_t)(filename[i]) >= 127)
927 {
928 return 0;
929 }
930 }
931
932 return 1;
933 }
934
935 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
936 {
937 if (0 == info->dir)
938 {
939 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
940 {
941 *((int *)data) = 1;
942 return 0;
943 }
944 }
945
946 return 0;
947 }
948
949 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
950 {
951 int i = 0;
952 int type = 0;
953 int ignore = 0;
954 grub_size_t len;
955 img_info *img;
956 img_info *tail;
957 img_iterator_node *tmp;
958 img_iterator_node *new_node;
959 img_iterator_node *node = (img_iterator_node *)data;
960
961 len = grub_strlen(filename);
962
963 if (info->dir)
964 {
965 if ((len == 1 && filename[0] == '.') ||
966 (len == 2 && filename[0] == '.' && filename[1] == '.'))
967 {
968 return 0;
969 }
970
971 if (!ventoy_img_name_valid(filename, len))
972 {
973 return 0;
974 }
975
976 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
977 {
978 return 0;
979 }
980
981 new_node = grub_zalloc(sizeof(img_iterator_node));
982 if (new_node)
983 {
984 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
985
986 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
987 if (ignore)
988 {
989 debug("Directory %s ignored...\n", new_node->dir);
990 grub_free(new_node);
991 return 0;
992 }
993
994 new_node->tail = node->tail;
995
996 new_node->parent = node;
997 if (!node->firstchild)
998 {
999 node->firstchild = new_node;
1000 }
1001
1002 if (g_img_iterator_tail)
1003 {
1004 g_img_iterator_tail->next = new_node;
1005 g_img_iterator_tail = new_node;
1006 }
1007 else
1008 {
1009 g_img_iterator_head.next = new_node;
1010 g_img_iterator_tail = new_node;
1011 }
1012 }
1013 }
1014 else
1015 {
1016 debug("Find a file %s\n", filename);
1017 if (len <= 4)
1018 {
1019 return 0;
1020 }
1021
1022 if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
1023 {
1024 type = img_type_iso;
1025 }
1026 else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1027 {
1028 type = img_type_wim;
1029 }
1030 #ifdef GRUB_MACHINE_EFI
1031 else if (0 == grub_strcasecmp(filename + len - 4, ".efi"))
1032 {
1033 type = img_type_efi;
1034 }
1035 #endif
1036 else if (0 == grub_strcasecmp(filename + len - 4, ".img"))
1037 {
1038 if (len == 18 && grub_strncmp(filename, "ventoy_wimboot", 14) == 0)
1039 {
1040 return 0;
1041 }
1042 type = img_type_img;
1043 }
1044 else
1045 {
1046 return 0;
1047 }
1048
1049 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1050 {
1051 return 0;
1052 }
1053
1054 img = grub_zalloc(sizeof(img_info));
1055 if (img)
1056 {
1057 img->type = type;
1058 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1059
1060 for (i = 0; i < (int)len; i++)
1061 {
1062 if (filename[i] == ' ' || filename[i] == '\t' || (0 == grub_isprint(filename[i])))
1063 {
1064 img->name[i] = '*';
1065 img->unsupport = 1;
1066 }
1067 }
1068
1069 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1070
1071 img->size = info->size;
1072 if (0 == img->size)
1073 {
1074 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1075 }
1076
1077 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1078 {
1079 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1080 grub_free(img);
1081 return 0;
1082 }
1083
1084 if (g_ventoy_img_list)
1085 {
1086 tail = *(node->tail);
1087 img->prev = tail;
1088 tail->next = img;
1089 }
1090 else
1091 {
1092 g_ventoy_img_list = img;
1093 }
1094
1095 img->id = g_ventoy_img_count;
1096 img->parent = node;
1097 if (node && NULL == node->firstiso)
1098 {
1099 node->firstiso = img;
1100 }
1101
1102 node->isocnt++;
1103 tmp = node->parent;
1104 while (tmp)
1105 {
1106 tmp->isocnt++;
1107 tmp = tmp->parent;
1108 }
1109
1110 *((img_info **)(node->tail)) = img;
1111 g_ventoy_img_count++;
1112
1113 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1114 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1115 if (!img->class)
1116 {
1117 img->class = g_menu_class[type];
1118 }
1119 img->menu_prefix = g_menu_prefix[type];
1120
1121 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1122 }
1123 }
1124
1125 return 0;
1126 }
1127
1128 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1129 {
1130 int len = GRUB_UINT_MAX;
1131 const char *value = NULL;
1132 char name[32] = {0};
1133 char plat[32] = {0};
1134 char guidstr[32] = {0};
1135 ventoy_guid guid = VENTOY_GUID;
1136 const char *fmt1 = NULL;
1137 const char *fmt2 = NULL;
1138 const char *fmt3 = NULL;
1139 grub_uint32_t *puint = (grub_uint32_t *)name;
1140 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1141 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1142 const char fmtcode[]={
1143 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1144 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1145 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1146 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1147 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1148 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1149 };
1150
1151 grub_memset(name, 0, sizeof(name));
1152 puint[0] = grub_swap_bytes32(0x56454e54);
1153 puint[3] = grub_swap_bytes32(0x4f4e0000);
1154 puint[2] = grub_swap_bytes32(0x45525349);
1155 puint[1] = grub_swap_bytes32(0x4f595f56);
1156 value = ventoy_get_env(name);
1157
1158 grub_memset(name, 0, sizeof(name));
1159 puint[1] = grub_swap_bytes32(0x5f544f50);
1160 puint[0] = grub_swap_bytes32(0x56544c45);
1161 fmt1 = ventoy_get_env(name);
1162 if (!fmt1)
1163 {
1164 fmt1 = fmtdata;
1165 }
1166
1167 grub_memset(name, 0, sizeof(name));
1168 puint[1] = grub_swap_bytes32(0x5f4c4654);
1169 puint[0] = grub_swap_bytes32(0x56544c45);
1170 fmt2 = ventoy_get_env(name);
1171
1172 grub_memset(name, 0, sizeof(name));
1173 puint[1] = grub_swap_bytes32(0x5f434c52);
1174 puint[0] = grub_swap_bytes32(0x56544c45);
1175 fmt3 = ventoy_get_env(name);
1176
1177 grub_memcpy(guidstr, &guid, sizeof(guid));
1178
1179 #if defined (GRUB_MACHINE_EFI)
1180 puint2[0] = grub_swap_bytes32(0x55454649);
1181 #else
1182 puint2[0] = grub_swap_bytes32(0x42494f53);
1183 #endif
1184
1185 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1186 #pragma GCC diagnostic push
1187 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1188 len = grub_snprintf(buffer, buflen, fmtcode,
1189 fmt1 ? fmt1 : fmtdata,
1190 fmt2 ? fmt2 : fmtdata + 4,
1191 value ? value : "", plat, guidstr,
1192 fmt3 ? fmt3 : fmtdata + 6);
1193 #pragma GCC diagnostic pop
1194
1195 grub_memset(name, 0, sizeof(name));
1196 puint[0] = grub_swap_bytes32(0x76746f79);
1197 puint[2] = grub_swap_bytes32(0x656e7365);
1198 puint[1] = grub_swap_bytes32(0x5f6c6963);
1199 ventoy_set_env(name, guidstr);
1200
1201 return len;
1202 }
1203
1204 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1205 {
1206 img_info *minimg = NULL;
1207 img_info *img = (img_info *)(node->firstiso);
1208
1209 while (img && (img_iterator_node *)(img->parent) == node)
1210 {
1211 if (img->select == 0 && (NULL == minimg || grub_strcmp(img->name, minimg->name) < 0))
1212 {
1213 minimg = img;
1214 }
1215 img = img->next;
1216 }
1217
1218 if (minimg)
1219 {
1220 minimg->select = 1;
1221 }
1222
1223 return minimg;
1224 }
1225
1226 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1227 {
1228 img_iterator_node *Minchild = NULL;
1229 img_iterator_node *child = node->firstchild;
1230
1231 while (child && child->parent == node)
1232 {
1233 if (child->select == 0 && (NULL == Minchild || grub_strcmp(child->dir, Minchild->dir) < 0))
1234 {
1235 Minchild = child;
1236 }
1237 child = child->next;
1238 }
1239
1240 if (Minchild)
1241 {
1242 Minchild->select = 1;
1243 }
1244
1245 return Minchild;
1246 }
1247
1248 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1249 {
1250 int offset = 1;
1251 img_info *img = NULL;
1252 const char *dir_class = NULL;
1253 const char *dir_alias = NULL;
1254 img_iterator_node *child = NULL;
1255
1256 if (node->isocnt == 0 || node->done == 1)
1257 {
1258 return 0;
1259 }
1260
1261 if (node->parent && node->parent->dirlen < node->dirlen)
1262 {
1263 offset = node->parent->dirlen;
1264 }
1265
1266 if (node == &g_img_iterator_head)
1267 {
1268 if (g_default_menu_mode == 0)
1269 {
1270 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1271 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1272 " echo 'return ...' \n"
1273 "}\n", "<--");
1274 }
1275 }
1276 else
1277 {
1278 node->dir[node->dirlen - 1] = 0;
1279 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1280 if (!dir_class)
1281 {
1282 dir_class = "vtoydir";
1283 }
1284
1285 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1286 if (dir_alias)
1287 {
1288 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1289 "submenu \"%-10s %s\" --class=\"%s\" {\n",
1290 "DIR", dir_alias, dir_class);
1291 }
1292 else
1293 {
1294 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1295 "submenu \"%-10s [%s]\" --class=\"%s\" {\n",
1296 "DIR", node->dir + offset, dir_class);
1297 }
1298
1299 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1300 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1301 " echo 'return ...' \n"
1302 "}\n", "<--");
1303 }
1304
1305 while ((child = ventoy_get_min_child(node)) != NULL)
1306 {
1307 ventoy_dynamic_tree_menu(child);
1308 }
1309
1310 while ((img = ventoy_get_min_iso(node)) != NULL)
1311 {
1312 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1313 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1314 " %s_%s \n"
1315 "}\n",
1316 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1317 img->unsupport ? "[unsupported] " : "",
1318 img->alias ? img->alias : img->name, img->class, img->id,
1319 img->menu_prefix,
1320 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1321 }
1322
1323 if (node != &g_img_iterator_head)
1324 {
1325 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1326 }
1327
1328 node->done = 1;
1329 return 0;
1330 }
1331
1332 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1333 {
1334 int len;
1335 grub_fs_t fs;
1336 grub_device_t dev = NULL;
1337 img_info *cur = NULL;
1338 img_info *tail = NULL;
1339 img_info *default_node = NULL;
1340 const char *strdata = NULL;
1341 char *device_name = NULL;
1342 const char *default_image = NULL;
1343 int img_len = 0;
1344 char buf[32];
1345 img_iterator_node *node = NULL;
1346 img_iterator_node *tmp = NULL;
1347
1348 (void)ctxt;
1349
1350 if (argc != 2)
1351 {
1352 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1353 }
1354
1355 if (g_ventoy_img_list || g_ventoy_img_count)
1356 {
1357 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1358 }
1359
1360 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1361 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1362 {
1363 g_filt_dot_underscore_file = 1;
1364 }
1365
1366 device_name = grub_file_get_device_name(args[0]);
1367 if (!device_name)
1368 {
1369 goto fail;
1370 }
1371
1372 g_enum_dev = dev = grub_device_open(device_name);
1373 if (!dev)
1374 {
1375 goto fail;
1376 }
1377
1378 g_enum_fs = fs = grub_fs_probe(dev);
1379 if (!fs)
1380 {
1381 goto fail;
1382 }
1383
1384 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1385 {
1386 debug("unsupported fs:<%s>\n", fs->name);
1387 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1388 goto fail;
1389 }
1390
1391 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1392 if (strdata && strdata[0] == '1')
1393 {
1394 g_default_menu_mode = 1;
1395 }
1396
1397 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
1398
1399 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
1400
1401 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1402 if (strdata && strdata[0] == '/')
1403 {
1404 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
1405 if (g_img_iterator_head.dir[len - 1] != '/')
1406 {
1407 g_img_iterator_head.dir[len++] = '/';
1408 }
1409 g_img_iterator_head.dirlen = len;
1410 }
1411 else
1412 {
1413 g_img_iterator_head.dirlen = 1;
1414 grub_strcpy(g_img_iterator_head.dir, "/");
1415 }
1416
1417 g_img_iterator_head.tail = &tail;
1418
1419 for (node = &g_img_iterator_head; node; node = node->next)
1420 {
1421 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1422 }
1423
1424 for (node = &g_img_iterator_head; node; node = node->next)
1425 {
1426 ventoy_dynamic_tree_menu(node);
1427 }
1428
1429 /* free node */
1430 node = g_img_iterator_head.next;
1431 while (node)
1432 {
1433 tmp = node->next;
1434 grub_free(node);
1435 node = tmp;
1436 }
1437
1438 /* sort image list by image name */
1439 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1440 {
1441 for (tail = cur->next; tail; tail = tail->next)
1442 {
1443 if (ventoy_cmp_img(cur, tail) > 0)
1444 {
1445 ventoy_swap_img(cur, tail);
1446 }
1447 }
1448 }
1449
1450 if (g_default_menu_mode == 1)
1451 {
1452 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1453 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1454 " echo 'return ...' \n"
1455 "}\n", "<--");
1456 }
1457
1458 if (g_default_menu_mode == 0)
1459 {
1460 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1461 if (default_image)
1462 {
1463 img_len = grub_strlen(default_image);
1464 }
1465 }
1466
1467 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1468 {
1469 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1470 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1471 " %s_%s \n"
1472 "}\n",
1473 cur->unsupport ? "[unsupported] " : "",
1474 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
1475 cur->menu_prefix,
1476 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
1477
1478 if (g_default_menu_mode == 0 && default_image && default_node == NULL)
1479 {
1480 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1481 {
1482 default_node = cur;
1483 }
1484 }
1485 }
1486
1487 if (default_node)
1488 {
1489 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1490 }
1491
1492 g_list_script_buf[g_list_script_pos] = 0;
1493
1494 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1495 grub_env_set(args[1], buf);
1496
1497 fail:
1498
1499 check_free(device_name, grub_free);
1500 check_free(dev, grub_device_close);
1501
1502 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1503 }
1504
1505
1506 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1507 {
1508 img_info *next = NULL;
1509 img_info *cur = g_ventoy_img_list;
1510
1511 (void)ctxt;
1512 (void)argc;
1513 (void)args;
1514
1515 while (cur)
1516 {
1517 next = cur->next;
1518 grub_free(cur);
1519 cur = next;
1520 }
1521
1522 g_ventoy_img_list = NULL;
1523 g_ventoy_img_count = 0;
1524
1525 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1526 }
1527
1528 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1529 {
1530 long img_id = 0;
1531 img_info *cur = g_ventoy_img_list;
1532
1533 (void)ctxt;
1534
1535 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1536 {
1537 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
1538 }
1539
1540 img_id = grub_strtol(args[0], NULL, 10);
1541 if (img_id >= g_ventoy_img_count)
1542 {
1543 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
1544 }
1545
1546 debug("Find image %ld name \n", img_id);
1547
1548 while (cur && img_id > 0)
1549 {
1550 img_id--;
1551 cur = cur->next;
1552 }
1553
1554 if (!cur)
1555 {
1556 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
1557 }
1558
1559 debug("image name is %s\n", cur->name);
1560
1561 grub_env_set(args[1], cur->name);
1562
1563 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1564 }
1565
1566 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
1567 {
1568 int img_id = 0;
1569 char value[32];
1570 char *pos = NULL;
1571 const char *id = NULL;
1572 img_info *cur = g_ventoy_img_list;
1573
1574 (void)ctxt;
1575
1576 if (argc < 1 || argc > 2)
1577 {
1578 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
1579 }
1580
1581 id = grub_env_get("chosen");
1582
1583 pos = grub_strstr(id, "VID_");
1584 if (pos)
1585 {
1586 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
1587 }
1588 else
1589 {
1590 img_id = (int)grub_strtoul(id, NULL, 10);
1591 }
1592
1593 while (cur)
1594 {
1595 if (img_id == cur->id)
1596 {
1597 break;
1598 }
1599 cur = cur->next;
1600 }
1601
1602 if (!cur)
1603 {
1604 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
1605 }
1606
1607 grub_env_set(args[0], cur->path);
1608
1609 if (argc > 1)
1610 {
1611 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
1612 grub_env_set(args[1], value);
1613 }
1614
1615 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1616 }
1617
1618 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
1619 {
1620 grub_disk_t disk;
1621 char *device_name;
1622 char *pos;
1623 char *pos2;
1624
1625 device_name = grub_file_get_device_name(filename);
1626 if (!device_name)
1627 {
1628 return 1;
1629 }
1630
1631 pos = device_name;
1632 if (pos[0] == '(')
1633 {
1634 pos++;
1635 }
1636
1637 pos2 = grub_strstr(pos, ",");
1638 if (!pos2)
1639 {
1640 pos2 = grub_strstr(pos, ")");
1641 }
1642
1643 if (pos2)
1644 {
1645 *pos2 = 0;
1646 }
1647
1648 disk = grub_disk_open(pos);
1649 if (disk)
1650 {
1651 grub_disk_read(disk, 0, 0x180, 16, guid);
1652 grub_disk_close(disk);
1653 }
1654 else
1655 {
1656 return 1;
1657 }
1658
1659 grub_free(device_name);
1660 return 0;
1661 }
1662
1663 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
1664 {
1665 eltorito_descriptor desc;
1666
1667 grub_memset(&desc, 0, sizeof(desc));
1668 grub_file_seek(file, 17 * 2048);
1669 grub_file_read(file, &desc, sizeof(desc));
1670
1671 if (desc.type != 0 || desc.version != 1)
1672 {
1673 return 0;
1674 }
1675
1676 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
1677 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
1678 {
1679 return 0;
1680 }
1681
1682 return desc.sector;
1683 }
1684
1685 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
1686 {
1687 int i;
1688 int x86count = 0;
1689 grub_uint8_t buf[512];
1690
1691 grub_file_seek(file, sector * 2048);
1692 grub_file_read(file, buf, sizeof(buf));
1693
1694 if (buf[0] == 0x01 && buf[1] == 0xEF)
1695 {
1696 debug("%s efi eltorito in Validation Entry\n", file->name);
1697 return 1;
1698 }
1699
1700 if (buf[0] == 0x01 && buf[1] == 0x00)
1701 {
1702 x86count++;
1703 }
1704
1705 for (i = 64; i < (int)sizeof(buf); i += 32)
1706 {
1707 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
1708 {
1709 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1710 return 1;
1711 }
1712
1713 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
1714 {
1715 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1716 return 1;
1717 }
1718 }
1719
1720 debug("%s does not contain efi eltorito\n", file->name);
1721 return 0;
1722 }
1723
1724 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1725 {
1726 char *pos;
1727 const char *fs = NULL;
1728 const char *cdprompt = NULL;
1729 grub_uint32_t i;
1730 grub_uint8_t chksum = 0;
1731 grub_disk_t disk;
1732
1733 disk = file->device->disk;
1734 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1735
1736 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1737 param->vtoy_disk_part_id = disk->partition->number + 1;
1738 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
1739
1740 pos = grub_strstr(file->name, "/");
1741 if (!pos)
1742 {
1743 pos = file->name;
1744 }
1745
1746 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1747
1748 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1749
1750 param->vtoy_img_size = file->size;
1751
1752 param->vtoy_reserved[0] = g_ventoy_break_level;
1753 param->vtoy_reserved[1] = g_ventoy_debug_level;
1754
1755 param->vtoy_reserved[2] = g_ventoy_chain_type;
1756
1757 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1758 param->vtoy_reserved[4] = 0;
1759 if (g_ventoy_chain_type == 1) /* Windows */
1760 {
1761 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1762 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
1763 {
1764 param->vtoy_reserved[4] = 1;
1765 }
1766 }
1767
1768 fs = ventoy_get_env("ventoy_fs_probe");
1769 if (fs && grub_strcmp(fs, "udf") == 0)
1770 {
1771 param->vtoy_reserved[3] = 1;
1772 }
1773
1774 /* calculate checksum */
1775 for (i = 0; i < sizeof(ventoy_os_param); i++)
1776 {
1777 chksum += *((grub_uint8_t *)param + i);
1778 }
1779 param->chksum = (grub_uint8_t)(0x100 - chksum);
1780
1781 return;
1782 }
1783
1784 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1785 {
1786 grub_uint32_t i = 0;
1787 grub_uint64_t total = 0;
1788 ventoy_img_chunk *chunk = NULL;
1789
1790 for (i = 0; i < chunklist->cur_chunk; i++)
1791 {
1792 chunk = chunklist->chunk + i;
1793
1794 if (chunk->disk_start_sector <= start)
1795 {
1796 debug("%u disk start invalid %lu\n", i, (ulong)start);
1797 return 1;
1798 }
1799
1800 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
1801 }
1802
1803 if (total != ((file->size + 511) / 512))
1804 {
1805 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
1806 return 1;
1807 }
1808
1809 return 0;
1810 }
1811
1812 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1813 {
1814 int fs_type;
1815 grub_uint32_t i = 0;
1816 grub_uint32_t sector = 0;
1817 grub_uint32_t count = 0;
1818 grub_off_t size = 0;
1819 grub_off_t read = 0;
1820
1821 fs_type = ventoy_get_fs_type(file->fs->name);
1822 if (fs_type == ventoy_fs_exfat)
1823 {
1824 grub_fat_get_file_chunk(start, file, chunklist);
1825 }
1826 else if (fs_type == ventoy_fs_ext)
1827 {
1828 grub_ext_get_file_chunk(start, file, chunklist);
1829 }
1830 else
1831 {
1832 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
1833 file->read_hook_data = chunklist;
1834
1835 for (size = file->size; size > 0; size -= read)
1836 {
1837 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
1838 grub_file_read(file, NULL, read);
1839 }
1840
1841 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
1842 {
1843 chunklist->chunk[i].disk_start_sector += start;
1844 chunklist->chunk[i].disk_end_sector += start;
1845 }
1846
1847 if (ventoy_fs_udf == fs_type)
1848 {
1849 for (i = 0; i < chunklist->cur_chunk; i++)
1850 {
1851 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
1852 chunklist->chunk[i].img_start_sector = sector;
1853 chunklist->chunk[i].img_end_sector = sector + count - 1;
1854 sector += count;
1855 }
1856 }
1857 }
1858
1859 return 0;
1860 }
1861
1862 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1863 {
1864 int rc;
1865 grub_file_t file;
1866 grub_disk_addr_t start;
1867
1868 (void)ctxt;
1869 (void)argc;
1870
1871 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1872 if (!file)
1873 {
1874 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1875 }
1876
1877 if (g_img_chunk_list.chunk)
1878 {
1879 grub_free(g_img_chunk_list.chunk);
1880 }
1881
1882 /* get image chunk data */
1883 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1884 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1885 if (NULL == g_img_chunk_list.chunk)
1886 {
1887 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1888 }
1889
1890 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1891 g_img_chunk_list.cur_chunk = 0;
1892
1893 start = file->device->disk->partition->start;
1894
1895 ventoy_get_block_list(file, &g_img_chunk_list, start);
1896
1897 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
1898 grub_file_close(file);
1899
1900 if (rc)
1901 {
1902 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
1903 }
1904
1905 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1906 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1907 }
1908
1909 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1910 {
1911 int i = 0;
1912 int pos = 0;
1913 char *buf = NULL;
1914 char configfile[128];
1915 install_template *node = NULL;
1916
1917 (void)ctxt;
1918 (void)argc;
1919 (void)args;
1920
1921 debug("select auto installation argc:%d\n", argc);
1922
1923 if (argc < 1)
1924 {
1925 return 0;
1926 }
1927
1928 node = ventoy_plugin_find_install_template(args[0]);
1929 if (!node)
1930 {
1931 debug("Auto install template not found for %s\n", args[0]);
1932 return 0;
1933 }
1934
1935 if (node->autosel >= 0 && node->autosel <= node->templatenum)
1936 {
1937 node->cursel = node->autosel - 1;
1938 debug("Auto install template auto select %d\n", node->autosel);
1939 return 0;
1940 }
1941
1942 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
1943 if (!buf)
1944 {
1945 return 0;
1946 }
1947
1948 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
1949 " echo %s\n}\n", "123");
1950
1951 for (i = 0; i < node->templatenum; i++)
1952 {
1953 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
1954 " echo 123\n}\n",
1955 node->templatepath[i].path);
1956 }
1957
1958 g_ventoy_menu_esc = 1;
1959 g_ventoy_suppress_esc = 1;
1960
1961 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
1962 grub_script_execute_sourcecode(configfile);
1963
1964 g_ventoy_menu_esc = 0;
1965 g_ventoy_suppress_esc = 0;
1966
1967 grub_free(buf);
1968
1969 node->cursel = g_ventoy_last_entry - 1;
1970
1971 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1972 }
1973
1974 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
1975 {
1976 int i = 0;
1977 int pos = 0;
1978 char *buf = NULL;
1979 char configfile[128];
1980 persistence_config *node;
1981
1982 (void)ctxt;
1983 (void)argc;
1984 (void)args;
1985
1986 debug("select persistence argc:%d\n", argc);
1987
1988 if (argc < 1)
1989 {
1990 return 0;
1991 }
1992
1993 node = ventoy_plugin_find_persistent(args[0]);
1994 if (!node)
1995 {
1996 debug("Persistence image not found for %s\n", args[0]);
1997 return 0;
1998 }
1999
2000 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2001 {
2002 node->cursel = node->autosel - 1;
2003 debug("Persistence image auto select %d\n", node->autosel);
2004 return 0;
2005 }
2006
2007 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2008 if (!buf)
2009 {
2010 return 0;
2011 }
2012
2013 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2014 " echo %s\n}\n", "123");
2015
2016 for (i = 0; i < node->backendnum; i++)
2017 {
2018 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2019 " echo 123\n}\n",
2020 node->backendpath[i].path);
2021
2022 }
2023
2024 g_ventoy_menu_esc = 1;
2025 g_ventoy_suppress_esc = 1;
2026
2027 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2028 grub_script_execute_sourcecode(configfile);
2029
2030 g_ventoy_menu_esc = 0;
2031 g_ventoy_suppress_esc = 0;
2032
2033 grub_free(buf);
2034
2035 node->cursel = g_ventoy_last_entry - 1;
2036
2037 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2038 }
2039
2040 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2041 {
2042 grub_uint32_t i;
2043 ventoy_img_chunk *cur;
2044
2045 (void)ctxt;
2046 (void)argc;
2047 (void)args;
2048
2049 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2050 {
2051 cur = g_img_chunk_list.chunk + i;
2052 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2053 cur->img_start_sector, cur->img_end_sector,
2054 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2055 );
2056 }
2057
2058 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2059 }
2060
2061 #ifdef GRUB_MACHINE_EFI
2062 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
2063 {
2064 (void)ctxt;
2065 (void)argc;
2066 (void)args;
2067 return 0;
2068 }
2069 #else
2070 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
2071 {
2072 int rc = 0;
2073 ulong chain_len = 0;
2074 char *chain_data = NULL;
2075 char *relocator_addr = NULL;
2076 grub_relocator_chunk_t ch;
2077 struct grub_relocator *relocator = NULL;
2078 char envbuf[64] = { 0 };
2079
2080 (void)ctxt;
2081 (void)argc;
2082 (void)args;
2083
2084 if (argc != 2)
2085 {
2086 return 1;
2087 }
2088
2089 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
2090 chain_len = grub_strtoul(args[1], NULL, 10);
2091
2092 relocator = grub_relocator_new ();
2093 if (!relocator)
2094 {
2095 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
2096 return 1;
2097 }
2098
2099 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
2100 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2101 chain_len);
2102 if (rc)
2103 {
2104 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
2105 grub_relocator_unload (relocator);
2106 return 1;
2107 }
2108
2109 relocator_addr = get_virtual_current_address(ch);
2110
2111 grub_memcpy(relocator_addr, chain_data, chain_len);
2112
2113 grub_relocator_unload (relocator);
2114
2115 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
2116 grub_env_set("vtoy_chain_relocator_addr", envbuf);
2117
2118 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2119 }
2120 #endif
2121
2122 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2123 {
2124 grub_uint32_t i;
2125 grub_file_t file;
2126 ventoy_img_chunk_list chunklist;
2127
2128 (void)ctxt;
2129 (void)argc;
2130
2131 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2132 if (!file)
2133 {
2134 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2135 }
2136
2137 /* get image chunk data */
2138 grub_memset(&chunklist, 0, sizeof(chunklist));
2139 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2140 if (NULL == chunklist.chunk)
2141 {
2142 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2143 }
2144
2145 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2146 chunklist.cur_chunk = 0;
2147
2148 ventoy_get_block_list(file, &chunklist, 0);
2149
2150 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2151 {
2152 grub_printf("########## UNSUPPORTED ###############\n");
2153 }
2154
2155 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2156
2157 for (i = 0; i < chunklist.cur_chunk; i++)
2158 {
2159 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2160 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2161 }
2162
2163 grub_printf("\n==================================\n");
2164
2165 for (i = 0; i < chunklist.cur_chunk; i++)
2166 {
2167 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2168 (ulonglong)chunklist.chunk[i].img_start_sector,
2169 (ulonglong)chunklist.chunk[i].img_end_sector,
2170 (ulonglong)chunklist.chunk[i].disk_start_sector,
2171 (ulonglong)chunklist.chunk[i].disk_end_sector
2172 );
2173 }
2174
2175 grub_free(chunklist.chunk);
2176 grub_file_close(file);
2177
2178 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2179 }
2180
2181 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2182 {
2183 int i;
2184 ventoy_grub_param_file_replace *replace = NULL;
2185
2186 (void)ctxt;
2187 (void)argc;
2188 (void)args;
2189
2190 if (argc >= 2)
2191 {
2192 replace = &(g_grub_param->file_replace);
2193 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2194
2195 replace->old_name_cnt = 0;
2196 for (i = 0; i < 4 && i + 1 < argc; i++)
2197 {
2198 replace->old_name_cnt++;
2199 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2200 }
2201
2202 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2203 }
2204
2205 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2206 }
2207
2208 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2209 {
2210 (void)ctxt;
2211 (void)argc;
2212 (void)args;
2213
2214 if (argc == 0)
2215 {
2216 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2217 grub_printf("%s", g_list_script_buf);
2218 }
2219 else
2220 {
2221 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2222 grub_printf("%s", g_tree_script_buf);
2223 }
2224
2225 return 0;
2226 }
2227
2228 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2229 {
2230 img_info *cur = g_ventoy_img_list;
2231
2232 (void)ctxt;
2233 (void)argc;
2234 (void)args;
2235
2236 while (cur)
2237 {
2238 grub_printf("path:<%s> id=%d\n", cur->path, cur->id);
2239 grub_printf("name:<%s>\n\n", cur->name);
2240 cur = cur->next;
2241 }
2242
2243 return 0;
2244 }
2245
2246 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2247 {
2248 (void)ctxt;
2249 (void)argc;
2250 (void)args;
2251
2252 ventoy_plugin_dump_injection();
2253
2254 return 0;
2255 }
2256
2257 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2258 {
2259 (void)ctxt;
2260 (void)argc;
2261 (void)args;
2262
2263 ventoy_plugin_dump_auto_install();
2264
2265 return 0;
2266 }
2267
2268 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2269 {
2270 (void)ctxt;
2271 (void)argc;
2272 (void)args;
2273
2274 ventoy_plugin_dump_persistence();
2275
2276 return 0;
2277 }
2278
2279 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2280 {
2281 (void)ctxt;
2282 (void)argc;
2283 (void)args;
2284
2285 if (argc != 1)
2286 {
2287 return 1;
2288 }
2289
2290 if (args[0][0] == '0')
2291 {
2292 return g_ventoy_memdisk_mode ? 0 : 1;
2293 }
2294 else if (args[0][0] == '1')
2295 {
2296 return g_ventoy_iso_raw ? 0 : 1;
2297 }
2298 else if (args[0][0] == '2')
2299 {
2300 return g_ventoy_iso_uefi_drv ? 0 : 1;
2301 }
2302
2303 return 1;
2304 }
2305
2306 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2307 {
2308 static int configfile_mode = 0;
2309 char memfile[128] = {0};
2310
2311 (void)ctxt;
2312 (void)argc;
2313 (void)args;
2314
2315 /*
2316 * args[0]: 0:normal 1:configfile
2317 * args[1]: 0:list_buf 1:tree_buf
2318 */
2319
2320 if (argc != 2)
2321 {
2322 debug("Invalid argc %d\n", argc);
2323 return 0;
2324 }
2325
2326 if (args[0][0] == '0')
2327 {
2328 if (args[1][0] == '0')
2329 {
2330 grub_script_execute_sourcecode(g_list_script_buf);
2331 }
2332 else
2333 {
2334 grub_script_execute_sourcecode(g_tree_script_buf);
2335 }
2336 }
2337 else
2338 {
2339 if (configfile_mode)
2340 {
2341 debug("Now already in F3 mode %d\n", configfile_mode);
2342 return 0;
2343 }
2344
2345 if (args[1][0] == '0')
2346 {
2347 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2348 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2349 }
2350 else
2351 {
2352 g_ventoy_last_entry = -1;
2353 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2354 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2355 }
2356
2357 configfile_mode = 1;
2358 grub_script_execute_sourcecode(memfile);
2359 configfile_mode = 0;
2360 }
2361
2362 return 0;
2363 }
2364
2365 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2366 {
2367 grub_file_t file;
2368
2369 (void)ctxt;
2370
2371 if (argc != 1)
2372 {
2373 return 1;
2374 }
2375
2376 g_ventoy_case_insensitive = 1;
2377 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2378 g_ventoy_case_insensitive = 0;
2379
2380 grub_errno = 0;
2381
2382 if (file)
2383 {
2384 grub_file_close(file);
2385 return 0;
2386 }
2387 return 1;
2388 }
2389
2390 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
2391 {
2392 int id = 0;
2393 int find = 0;
2394 grub_disk_t disk;
2395 const char *isopath = NULL;
2396 char hdname[32];
2397 ventoy_mbr_head mbr;
2398
2399 (void)ctxt;
2400 (void)argc;
2401
2402 if (argc != 1)
2403 {
2404 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
2405 }
2406
2407 isopath = grub_env_get("vtoy_iso_part");
2408 if (!isopath)
2409 {
2410 debug("isopath is null %p\n", isopath);
2411 return 0;
2412 }
2413
2414 debug("isopath is %s\n", isopath);
2415
2416 for (id = 0; id < 30 && (find == 0); id++)
2417 {
2418 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
2419 if (grub_strstr(isopath, hdname))
2420 {
2421 debug("skip %s ...\n", hdname);
2422 continue;
2423 }
2424
2425 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
2426
2427 disk = grub_disk_open(hdname);
2428 if (!disk)
2429 {
2430 debug("%s not exist\n", hdname);
2431 break;
2432 }
2433
2434 grub_memset(&mbr, 0, sizeof(mbr));
2435 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
2436 {
2437 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
2438 {
2439 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
2440 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
2441 {
2442
2443 grub_env_set(args[0], hdname);
2444 find = 1;
2445 }
2446 }
2447 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
2448 }
2449 else
2450 {
2451 debug("read %s failed\n", hdname);
2452 }
2453
2454 grub_disk_close(disk);
2455 }
2456
2457 return 0;
2458 }
2459
2460 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
2461 {
2462 int len = 1024;
2463 grub_file_t file;
2464 char *buf = NULL;
2465
2466 (void)ctxt;
2467 (void)argc;
2468
2469 if (argc != 2)
2470 {
2471 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
2472 }
2473
2474 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2475 if (!file)
2476 {
2477 debug("failed to open file %s\n", args[0]);
2478 return 0;
2479 }
2480
2481 buf = grub_malloc(len);
2482 if (!buf)
2483 {
2484 goto end;
2485 }
2486
2487 buf[len - 1] = 0;
2488 grub_file_read(file, buf, len - 1);
2489
2490 ventoy_get_line(buf);
2491 ventoy_set_env(args[1], buf);
2492
2493 end:
2494
2495 grub_check_free(buf);
2496 grub_file_close(file);
2497
2498 return 0;
2499 }
2500
2501 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
2502 {
2503 int len;
2504 grub_file_t file;
2505 char buf[64];
2506 ventoy_iso9660_vd pvd;
2507
2508 (void)ctxt;
2509 (void)argc;
2510
2511 if (argc != 3)
2512 {
2513 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid \n", cmd_raw_name);
2514 }
2515
2516 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2517 if (!file)
2518 {
2519 debug("failed to open file %s\n", args[0]);
2520 return 0;
2521 }
2522
2523 grub_file_seek(file, 16 * 2048);
2524 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
2525 if (len != sizeof(pvd))
2526 {
2527 debug("failed to read pvd %d\n", len);
2528 goto end;
2529 }
2530
2531 grub_memset(buf, 0, sizeof(buf));
2532 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
2533 ventoy_set_env(args[1], buf);
2534
2535 grub_memset(buf, 0, sizeof(buf));
2536 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
2537 ventoy_set_env(args[2], buf);
2538
2539 end:
2540 grub_file_close(file);
2541
2542 return 0;
2543 }
2544
2545 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
2546 {
2547 int len;
2548 grub_file_t file;
2549 char buf[64];
2550
2551 (void)ctxt;
2552 (void)argc;
2553
2554 if (argc != 2)
2555 {
2556 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
2557 }
2558
2559 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2560 if (!file)
2561 {
2562 debug("failed to open file %s\n", args[0]);
2563 return 0;
2564 }
2565
2566 grub_memset(buf, 0, sizeof(buf));
2567 grub_file_seek(file, 16 * 2048 + 813);
2568 len = (int)grub_file_read(file, buf, 17);
2569 if (len != 17)
2570 {
2571 debug("failed to read create date %d\n", len);
2572 goto end;
2573 }
2574
2575 ventoy_set_env(args[1], buf);
2576
2577 end:
2578 grub_file_close(file);
2579
2580 return 0;
2581 }
2582
2583 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
2584 {
2585 (void)ctxt;
2586 (void)argc;
2587 (void)args;
2588
2589 ventoy_env_hook_root(1);
2590
2591 return 0;
2592 }
2593
2594 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
2595 {
2596 (void)ctxt;
2597 (void)argc;
2598 (void)args;
2599
2600 ventoy_env_hook_root(0);
2601
2602 return 0;
2603 }
2604
2605 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
2606 {
2607 grub_uint64_t size = 0;
2608 grub_file_t file;
2609 va_list ap;
2610 char fullpath[256] = {0};
2611
2612 va_start (ap, fmt);
2613 grub_vsnprintf(fullpath, 255, fmt, ap);
2614 va_end (ap);
2615
2616 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
2617 if (!file)
2618 {
2619 debug("grub_file_open failed <%s>\n", fullpath);
2620 grub_errno = 0;
2621 return 0;
2622 }
2623
2624 size = file->size;
2625 grub_file_close(file);
2626 return size;
2627 }
2628
2629 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
2630 {
2631 va_list ap;
2632 grub_file_t file;
2633 char fullpath[256] = {0};
2634
2635 va_start (ap, fmt);
2636 grub_vsnprintf(fullpath, 255, fmt, ap);
2637 va_end (ap);
2638
2639 file = grub_file_open(fullpath, type);
2640 if (!file)
2641 {
2642 debug("grub_file_open failed <%s>\n", fullpath);
2643 grub_errno = 0;
2644 }
2645
2646 return file;
2647 }
2648
2649 int ventoy_is_file_exist(const char *fmt, ...)
2650 {
2651 va_list ap;
2652 int len;
2653 char *pos = NULL;
2654 char buf[256] = {0};
2655
2656 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
2657 pos = buf + 5;
2658
2659 va_start (ap, fmt);
2660 len = grub_vsnprintf(pos, 255, fmt, ap);
2661 va_end (ap);
2662
2663 grub_strncpy(pos + len, " ]", 2);
2664
2665 debug("script exec %s\n", buf);
2666
2667 if (0 == grub_script_execute_sourcecode(buf))
2668 {
2669 return 1;
2670 }
2671
2672 return 0;
2673 }
2674
2675 int ventoy_is_dir_exist(const char *fmt, ...)
2676 {
2677 va_list ap;
2678 int len;
2679 char *pos = NULL;
2680 char buf[256] = {0};
2681
2682 grub_snprintf(buf, sizeof(buf), "%s", "[ -d ");
2683 pos = buf + 5;
2684
2685 va_start (ap, fmt);
2686 len = grub_vsnprintf(pos, 255, fmt, ap);
2687 va_end (ap);
2688
2689 grub_strncpy(pos + len, " ]", 2);
2690
2691 debug("script exec %s\n", buf);
2692
2693 if (0 == grub_script_execute_sourcecode(buf))
2694 {
2695 return 1;
2696 }
2697
2698 return 0;
2699 }
2700
2701 static int ventoy_env_init(void)
2702 {
2703 char buf[64];
2704
2705 grub_env_set("vtdebug_flag", "");
2706
2707 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2708 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2709
2710 ventoy_filt_register(0, ventoy_wrapper_open);
2711
2712 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
2713 if (g_grub_param)
2714 {
2715 g_grub_param->grub_env_get = grub_env_get;
2716 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
2717 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
2718 grub_env_set("env_param", buf);
2719 }
2720
2721 return 0;
2722 }
2723
2724 static cmd_para ventoy_cmds[] =
2725 {
2726 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
2727 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
2728 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
2729 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2730 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2731 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
2732 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
2733 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
2734 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
2735 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
2736 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
2737 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
2738 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
2739 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
2740 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
2741 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
2742
2743 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
2744 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
2745
2746 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
2747 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
2748 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
2749 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
2750 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
2751 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
2752 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
2753 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
2754 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
2755 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
2756
2757 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
2758 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
2759 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
2760 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
2761 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
2762 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
2763
2764 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2765 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2766 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
2767 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
2768 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
2769 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
2770 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
2771 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
2772 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
2773 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
2774
2775 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
2776 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
2777 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
2778 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
2779 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
2780 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
2781 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
2782
2783 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
2784 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
2785 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
2786 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
2787
2788
2789 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
2790 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
2791
2792 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
2793 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
2794 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
2795 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
2796 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
2797 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
2798 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
2799 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
2800 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
2801
2802 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
2803 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
2804
2805 };
2806
2807
2808
2809 GRUB_MOD_INIT(ventoy)
2810 {
2811 grub_uint32_t i;
2812 cmd_para *cur = NULL;
2813
2814 ventoy_env_init();
2815
2816 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2817 {
2818 cur = ventoy_cmds + i;
2819 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
2820 cur->summary, cur->description, cur->parser);
2821 }
2822 }
2823
2824 GRUB_MOD_FINI(ventoy)
2825 {
2826 grub_uint32_t i;
2827
2828 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2829 {
2830 grub_unregister_extcmd(ventoy_cmds[i].cmd);
2831 }
2832 }
2833