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