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