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