]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
e86746ac8a0ef7e46c3fe671306e32a31b7f4db8
[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 ulonglong value1 = 0;
545 ulonglong 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_strtoull(args[0], NULL, 10);
554 value2 = grub_strtoull(args[1], NULL, 10);
555
556 grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1)));
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_time_checked = 0;
1988 g_enumerate_start_time_ms = grub_get_time_ms();
1989
1990 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1991 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1992 {
1993 g_filt_dot_underscore_file = 1;
1994 }
1995
1996 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1997 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1998 {
1999 g_sort_case_sensitive = 1;
2000 }
2001
2002 device_name = grub_file_get_device_name(args[0]);
2003 if (!device_name)
2004 {
2005 goto fail;
2006 }
2007
2008 g_enum_dev = dev = grub_device_open(device_name);
2009 if (!dev)
2010 {
2011 goto fail;
2012 }
2013
2014 g_enum_fs = fs = grub_fs_probe(dev);
2015 if (!fs)
2016 {
2017 goto fail;
2018 }
2019
2020 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2021 {
2022 debug("unsupported fs:<%s>\n", fs->name);
2023 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2024 goto fail;
2025 }
2026
2027 ventoy_set_env("vtoy_iso_fs", fs->name);
2028
2029 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2030 if (strdata && strdata[0] == '1')
2031 {
2032 g_default_menu_mode = 1;
2033 }
2034
2035 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2036
2037 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2038
2039 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2040 if (strdata && strdata[0] == '/')
2041 {
2042 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2043 if (g_img_iterator_head.dir[len - 1] != '/')
2044 {
2045 g_img_iterator_head.dir[len++] = '/';
2046 }
2047 g_img_iterator_head.dirlen = len;
2048 }
2049 else
2050 {
2051 g_img_iterator_head.dirlen = 1;
2052 grub_strcpy(g_img_iterator_head.dir, "/");
2053 }
2054
2055 g_img_iterator_head.tail = &tail;
2056
2057 for (node = &g_img_iterator_head; node; node = node->next)
2058 {
2059 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2060 }
2061
2062 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2063 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2064 {
2065 g_tree_view_menu_style = 1;
2066 }
2067
2068 ventoy_set_default_menu();
2069
2070 for (node = &g_img_iterator_head; node; node = node->next)
2071 {
2072 ventoy_dynamic_tree_menu(node);
2073 }
2074
2075 /* free node */
2076 node = g_img_iterator_head.next;
2077 while (node)
2078 {
2079 tmp = node->next;
2080 grub_free(node);
2081 node = tmp;
2082 }
2083
2084 /* sort image list by image name */
2085 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2086 {
2087 for (tail = cur->next; tail; tail = tail->next)
2088 {
2089 if (ventoy_cmp_img(cur, tail) > 0)
2090 {
2091 ventoy_swap_img(cur, tail);
2092 }
2093 }
2094 }
2095
2096 if (g_default_menu_mode == 1)
2097 {
2098 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2099 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2100 " echo 'return ...' \n"
2101 "}\n", "<--");
2102 }
2103
2104 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2105 {
2106 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2107 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2108 " %s_%s \n"
2109 "}\n",
2110 cur->unsupport ? "[***********] " : "",
2111 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2112 cur->menu_prefix,
2113 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2114 }
2115
2116 g_tree_script_buf[g_tree_script_pos] = 0;
2117 g_list_script_buf[g_list_script_pos] = 0;
2118
2119 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2120 grub_env_set(args[1], buf);
2121
2122 fail:
2123
2124 check_free(device_name, grub_free);
2125 check_free(dev, grub_device_close);
2126
2127 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2128 }
2129
2130
2131 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2132 {
2133 img_info *next = NULL;
2134 img_info *cur = g_ventoy_img_list;
2135
2136 (void)ctxt;
2137 (void)argc;
2138 (void)args;
2139
2140 while (cur)
2141 {
2142 next = cur->next;
2143 grub_free(cur);
2144 cur = next;
2145 }
2146
2147 g_ventoy_img_list = NULL;
2148 g_ventoy_img_count = 0;
2149
2150 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2151 }
2152
2153 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2154 {
2155 long img_id = 0;
2156 img_info *cur = g_ventoy_img_list;
2157
2158 (void)ctxt;
2159
2160 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2161 {
2162 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2163 }
2164
2165 img_id = grub_strtol(args[0], NULL, 10);
2166 if (img_id >= g_ventoy_img_count)
2167 {
2168 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2169 }
2170
2171 debug("Find image %ld name \n", img_id);
2172
2173 while (cur && img_id > 0)
2174 {
2175 img_id--;
2176 cur = cur->next;
2177 }
2178
2179 if (!cur)
2180 {
2181 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2182 }
2183
2184 debug("image name is %s\n", cur->name);
2185
2186 grub_env_set(args[1], cur->name);
2187
2188 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2189 }
2190
2191 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2192 {
2193 int img_id = 0;
2194 char value[32];
2195 char *pos = NULL;
2196 const char *id = NULL;
2197 img_info *cur = g_ventoy_img_list;
2198
2199 (void)ctxt;
2200
2201 if (argc < 1 || argc > 2)
2202 {
2203 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2204 }
2205
2206 id = grub_env_get("chosen");
2207
2208 pos = grub_strstr(id, "VID_");
2209 if (pos)
2210 {
2211 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2212 }
2213 else
2214 {
2215 img_id = (int)grub_strtoul(id, NULL, 10);
2216 }
2217
2218 while (cur)
2219 {
2220 if (img_id == cur->id)
2221 {
2222 break;
2223 }
2224 cur = cur->next;
2225 }
2226
2227 if (!cur)
2228 {
2229 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2230 }
2231
2232 grub_env_set(args[0], cur->path);
2233
2234 if (argc > 1)
2235 {
2236 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2237 grub_env_set(args[1], value);
2238 }
2239
2240 g_svd_replace_offset = 0;
2241
2242 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2243 }
2244
2245 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2246 {
2247 grub_disk_t disk;
2248 char *device_name;
2249 char *pos;
2250 char *pos2;
2251
2252 device_name = grub_file_get_device_name(filename);
2253 if (!device_name)
2254 {
2255 return 1;
2256 }
2257
2258 pos = device_name;
2259 if (pos[0] == '(')
2260 {
2261 pos++;
2262 }
2263
2264 pos2 = grub_strstr(pos, ",");
2265 if (!pos2)
2266 {
2267 pos2 = grub_strstr(pos, ")");
2268 }
2269
2270 if (pos2)
2271 {
2272 *pos2 = 0;
2273 }
2274
2275 disk = grub_disk_open(pos);
2276 if (disk)
2277 {
2278 grub_disk_read(disk, 0, 0x180, 16, guid);
2279 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2280 grub_disk_close(disk);
2281 }
2282 else
2283 {
2284 return 1;
2285 }
2286
2287 grub_free(device_name);
2288 return 0;
2289 }
2290
2291 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2292 {
2293 eltorito_descriptor desc;
2294
2295 grub_memset(&desc, 0, sizeof(desc));
2296 grub_file_seek(file, 17 * 2048);
2297 grub_file_read(file, &desc, sizeof(desc));
2298
2299 if (desc.type != 0 || desc.version != 1)
2300 {
2301 return 0;
2302 }
2303
2304 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2305 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2306 {
2307 return 0;
2308 }
2309
2310 return desc.sector;
2311 }
2312
2313 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2314 {
2315 int i;
2316 int x86count = 0;
2317 grub_uint8_t buf[512];
2318 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2319
2320 grub_file_seek(file, sector * 2048);
2321 grub_file_read(file, buf, sizeof(buf));
2322
2323 if (buf[0] == 0x01 && buf[1] == 0xEF)
2324 {
2325 debug("%s efi eltorito in Validation Entry\n", file->name);
2326 return 1;
2327 }
2328
2329 if (buf[0] == 0x01 && buf[1] == 0x00)
2330 {
2331 x86count++;
2332 }
2333
2334 for (i = 64; i < (int)sizeof(buf); i += 32)
2335 {
2336 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2337 {
2338 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2339 return 1;
2340 }
2341
2342 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2343 {
2344 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2345 return 1;
2346 }
2347 }
2348
2349 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2350 {
2351 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2352 {
2353 if (buf[36] == parttype[i])
2354 {
2355 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2356 return 1;
2357 }
2358 }
2359 }
2360
2361 debug("%s does not contain efi eltorito\n", file->name);
2362 return 0;
2363 }
2364
2365 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2366 {
2367 char *pos;
2368 const char *fs = NULL;
2369 const char *cdprompt = NULL;
2370 grub_uint32_t i;
2371 grub_uint8_t chksum = 0;
2372 grub_disk_t disk;
2373
2374 disk = file->device->disk;
2375 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2376
2377 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2378 param->vtoy_disk_part_id = disk->partition->number + 1;
2379 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2380
2381 pos = grub_strstr(file->name, "/");
2382 if (!pos)
2383 {
2384 pos = file->name;
2385 }
2386
2387 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2388
2389 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2390
2391 param->vtoy_img_size = file->size;
2392
2393 param->vtoy_reserved[0] = g_ventoy_break_level;
2394 param->vtoy_reserved[1] = g_ventoy_debug_level;
2395
2396 param->vtoy_reserved[2] = g_ventoy_chain_type;
2397
2398 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2399 param->vtoy_reserved[4] = 0;
2400 if (g_ventoy_chain_type == 1) /* Windows */
2401 {
2402 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2403 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2404 {
2405 param->vtoy_reserved[4] = 1;
2406 }
2407 }
2408
2409 fs = ventoy_get_env("ventoy_fs_probe");
2410 if (fs && grub_strcmp(fs, "udf") == 0)
2411 {
2412 param->vtoy_reserved[3] = 1;
2413 }
2414
2415 /* calculate checksum */
2416 for (i = 0; i < sizeof(ventoy_os_param); i++)
2417 {
2418 chksum += *((grub_uint8_t *)param + i);
2419 }
2420 param->chksum = (grub_uint8_t)(0x100 - chksum);
2421
2422 return;
2423 }
2424
2425 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2426 {
2427 grub_uint32_t i = 0;
2428 grub_uint64_t total = 0;
2429 ventoy_img_chunk *chunk = NULL;
2430
2431 for (i = 0; i < chunklist->cur_chunk; i++)
2432 {
2433 chunk = chunklist->chunk + i;
2434
2435 if (chunk->disk_start_sector <= start)
2436 {
2437 debug("%u disk start invalid %lu\n", i, (ulong)start);
2438 return 1;
2439 }
2440
2441 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2442 }
2443
2444 if (total != ((file->size + 511) / 512))
2445 {
2446 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2447 return 1;
2448 }
2449
2450 return 0;
2451 }
2452
2453 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2454 {
2455 int fs_type;
2456 int len;
2457 grub_uint32_t i = 0;
2458 grub_uint32_t sector = 0;
2459 grub_uint32_t count = 0;
2460 grub_off_t size = 0;
2461 grub_off_t read = 0;
2462
2463 fs_type = ventoy_get_fs_type(file->fs->name);
2464 if (fs_type == ventoy_fs_exfat)
2465 {
2466 grub_fat_get_file_chunk(start, file, chunklist);
2467 }
2468 else if (fs_type == ventoy_fs_ext)
2469 {
2470 grub_ext_get_file_chunk(start, file, chunklist);
2471 }
2472 else
2473 {
2474 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2475 file->read_hook_data = chunklist;
2476
2477 for (size = file->size; size > 0; size -= read)
2478 {
2479 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2480 grub_file_read(file, NULL, read);
2481 }
2482
2483 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2484 {
2485 chunklist->chunk[i].disk_start_sector += start;
2486 chunklist->chunk[i].disk_end_sector += start;
2487 }
2488
2489 if (ventoy_fs_udf == fs_type)
2490 {
2491 for (i = 0; i < chunklist->cur_chunk; i++)
2492 {
2493 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2494 chunklist->chunk[i].img_start_sector = sector;
2495 chunklist->chunk[i].img_end_sector = sector + count - 1;
2496 sector += count;
2497 }
2498 }
2499 }
2500
2501 len = (int)grub_strlen(file->name);
2502 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2503 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2504 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2505 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2506 {
2507 for (i = 0; i < chunklist->cur_chunk; i++)
2508 {
2509 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2510 if (count < 4)
2511 {
2512 count = 1;
2513 }
2514 else
2515 {
2516 count >>= 2;
2517 }
2518
2519 chunklist->chunk[i].img_start_sector = sector;
2520 chunklist->chunk[i].img_end_sector = sector + count - 1;
2521 sector += count;
2522 }
2523 }
2524
2525 return 0;
2526 }
2527
2528 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2529 {
2530 int rc;
2531 grub_file_t file;
2532 grub_disk_addr_t start;
2533
2534 (void)ctxt;
2535 (void)argc;
2536
2537 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2538 if (!file)
2539 {
2540 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2541 }
2542
2543 g_conf_replace_node = NULL;
2544 g_conf_replace_offset = 0;
2545
2546 if (g_img_chunk_list.chunk)
2547 {
2548 grub_free(g_img_chunk_list.chunk);
2549 }
2550
2551 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2552 {
2553 grub_file_close(file);
2554 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2555 }
2556
2557 /* get image chunk data */
2558 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2559 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2560 if (NULL == g_img_chunk_list.chunk)
2561 {
2562 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2563 }
2564
2565 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2566 g_img_chunk_list.cur_chunk = 0;
2567
2568 start = file->device->disk->partition->start;
2569
2570 ventoy_get_block_list(file, &g_img_chunk_list, start);
2571
2572 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2573 grub_file_close(file);
2574
2575 if (rc)
2576 {
2577 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2578 }
2579
2580 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2581 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2582 }
2583
2584 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2585 {
2586 grub_uint64_t offset = 0;
2587 grub_uint32_t align = 0;
2588 grub_file_t file = NULL;
2589 conf_replace *node = NULL;
2590
2591 (void)ctxt;
2592 (void)argc;
2593 (void)args;
2594
2595 debug("select conf replace argc:%d\n", argc);
2596
2597 if (argc < 2)
2598 {
2599 return 0;
2600 }
2601
2602 node = ventoy_plugin_find_conf_replace(args[1]);
2603 if (!node)
2604 {
2605 debug("Conf replace not found for %s\n", args[1]);
2606 goto end;
2607 }
2608
2609 debug("Find conf replace for %s\n", args[1]);
2610
2611 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2612 if (!file)
2613 {
2614 debug("<(loop)%s> NOT exist\n", node->orgconf);
2615 goto end;
2616 }
2617
2618 offset = grub_iso9660_get_last_file_dirent_pos(file);
2619 grub_file_close(file);
2620
2621 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2622 if (!file)
2623 {
2624 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2625 goto end;
2626 }
2627
2628 align = ((int)file->size + 2047) / 2048 * 2048;
2629
2630 if (align > vtoy_max_replace_file_size)
2631 {
2632 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2633 goto end;
2634 }
2635
2636 grub_file_read(file, g_conf_replace_new_buf, file->size);
2637 g_conf_replace_new_len = (int)file->size;
2638 g_conf_replace_new_len_align = align;
2639
2640 g_conf_replace_node = node;
2641 g_conf_replace_offset = offset + 2;
2642
2643 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2644
2645 end:
2646 if (file)
2647 {
2648 grub_file_close(file);
2649 }
2650 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2651 }
2652
2653 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2654 {
2655 int i = 0;
2656 int pos = 0;
2657 char *buf = NULL;
2658 char configfile[128];
2659 install_template *node = NULL;
2660
2661 (void)ctxt;
2662 (void)argc;
2663 (void)args;
2664
2665 debug("select auto installation argc:%d\n", argc);
2666
2667 if (argc < 1)
2668 {
2669 return 0;
2670 }
2671
2672 node = ventoy_plugin_find_install_template(args[0]);
2673 if (!node)
2674 {
2675 debug("Auto install template not found for %s\n", args[0]);
2676 return 0;
2677 }
2678
2679 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2680 {
2681 node->cursel = node->autosel - 1;
2682 debug("Auto install template auto select %d\n", node->autosel);
2683 return 0;
2684 }
2685
2686 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2687 if (!buf)
2688 {
2689 return 0;
2690 }
2691
2692 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2693 " echo %s\n}\n", "123");
2694
2695 for (i = 0; i < node->templatenum; i++)
2696 {
2697 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2698 " echo 123\n}\n",
2699 node->templatepath[i].path);
2700 }
2701
2702 g_ventoy_menu_esc = 1;
2703 g_ventoy_suppress_esc = 1;
2704
2705 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2706 grub_script_execute_sourcecode(configfile);
2707
2708 g_ventoy_menu_esc = 0;
2709 g_ventoy_suppress_esc = 0;
2710
2711 grub_free(buf);
2712
2713 node->cursel = g_ventoy_last_entry - 1;
2714
2715 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2716 }
2717
2718 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2719 {
2720 int i = 0;
2721 int pos = 0;
2722 char *buf = NULL;
2723 char configfile[128];
2724 persistence_config *node;
2725
2726 (void)ctxt;
2727 (void)argc;
2728 (void)args;
2729
2730 debug("select persistence argc:%d\n", argc);
2731
2732 if (argc < 1)
2733 {
2734 return 0;
2735 }
2736
2737 node = ventoy_plugin_find_persistent(args[0]);
2738 if (!node)
2739 {
2740 debug("Persistence image not found for %s\n", args[0]);
2741 return 0;
2742 }
2743
2744 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2745 {
2746 node->cursel = node->autosel - 1;
2747 debug("Persistence image auto select %d\n", node->autosel);
2748 return 0;
2749 }
2750
2751 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2752 if (!buf)
2753 {
2754 return 0;
2755 }
2756
2757 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2758 " echo %s\n}\n", "123");
2759
2760 for (i = 0; i < node->backendnum; i++)
2761 {
2762 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2763 " echo 123\n}\n",
2764 node->backendpath[i].path);
2765
2766 }
2767
2768 g_ventoy_menu_esc = 1;
2769 g_ventoy_suppress_esc = 1;
2770
2771 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2772 grub_script_execute_sourcecode(configfile);
2773
2774 g_ventoy_menu_esc = 0;
2775 g_ventoy_suppress_esc = 0;
2776
2777 grub_free(buf);
2778
2779 node->cursel = g_ventoy_last_entry - 1;
2780
2781 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2782 }
2783
2784 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2785 {
2786 grub_uint32_t i;
2787 ventoy_img_chunk *cur;
2788
2789 (void)ctxt;
2790 (void)argc;
2791 (void)args;
2792
2793 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2794 {
2795 cur = g_img_chunk_list.chunk + i;
2796 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2797 cur->img_start_sector, cur->img_end_sector,
2798 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2799 );
2800 }
2801
2802 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2803 }
2804
2805 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2806 {
2807 grub_uint32_t i;
2808 grub_file_t file;
2809 ventoy_img_chunk_list chunklist;
2810
2811 (void)ctxt;
2812 (void)argc;
2813
2814 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2815 if (!file)
2816 {
2817 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2818 }
2819
2820 /* get image chunk data */
2821 grub_memset(&chunklist, 0, sizeof(chunklist));
2822 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2823 if (NULL == chunklist.chunk)
2824 {
2825 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2826 }
2827
2828 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2829 chunklist.cur_chunk = 0;
2830
2831 ventoy_get_block_list(file, &chunklist, 0);
2832
2833 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2834 {
2835 grub_printf("########## UNSUPPORTED ###############\n");
2836 }
2837
2838 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2839
2840 for (i = 0; i < chunklist.cur_chunk; i++)
2841 {
2842 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2843 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2844 }
2845
2846 grub_printf("\n==================================\n");
2847
2848 for (i = 0; i < chunklist.cur_chunk; i++)
2849 {
2850 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2851 (ulonglong)chunklist.chunk[i].img_start_sector,
2852 (ulonglong)chunklist.chunk[i].img_end_sector,
2853 (ulonglong)chunklist.chunk[i].disk_start_sector,
2854 (ulonglong)chunklist.chunk[i].disk_end_sector
2855 );
2856 }
2857
2858 grub_free(chunklist.chunk);
2859 grub_file_close(file);
2860
2861 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2862 }
2863
2864 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2865 {
2866 int i;
2867 ventoy_grub_param_file_replace *replace = NULL;
2868
2869 (void)ctxt;
2870 (void)argc;
2871 (void)args;
2872
2873 if (argc >= 2)
2874 {
2875 replace = &(g_grub_param->file_replace);
2876 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2877
2878 replace->old_name_cnt = 0;
2879 for (i = 0; i < 4 && i + 1 < argc; i++)
2880 {
2881 replace->old_name_cnt++;
2882 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2883 }
2884
2885 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2886 }
2887
2888 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2889 }
2890
2891 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2892 {
2893 (void)ctxt;
2894 (void)argc;
2895 (void)args;
2896
2897 if (argc == 0)
2898 {
2899 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2900 grub_printf("%s", g_list_script_buf);
2901 }
2902 else
2903 {
2904 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2905 grub_printf("%s", g_tree_script_buf);
2906 }
2907
2908 return 0;
2909 }
2910
2911 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2912 {
2913 img_info *cur = g_ventoy_img_list;
2914
2915 (void)ctxt;
2916 (void)argc;
2917 (void)args;
2918
2919 while (cur)
2920 {
2921 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2922 grub_printf("name:<%s>\n\n", cur->name);
2923 cur = cur->next;
2924 }
2925
2926 return 0;
2927 }
2928
2929 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2930 {
2931 (void)ctxt;
2932 (void)argc;
2933 (void)args;
2934
2935 ventoy_plugin_dump_injection();
2936
2937 return 0;
2938 }
2939
2940 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2941 {
2942 (void)ctxt;
2943 (void)argc;
2944 (void)args;
2945
2946 ventoy_plugin_dump_auto_install();
2947
2948 return 0;
2949 }
2950
2951 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2952 {
2953 (void)ctxt;
2954 (void)argc;
2955 (void)args;
2956
2957 ventoy_plugin_dump_persistence();
2958
2959 return 0;
2960 }
2961
2962 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2963 {
2964 (void)ctxt;
2965 (void)argc;
2966 (void)args;
2967
2968 if (argc != 1)
2969 {
2970 return 1;
2971 }
2972
2973 if (args[0][0] == '0')
2974 {
2975 return g_ventoy_memdisk_mode ? 0 : 1;
2976 }
2977 else if (args[0][0] == '1')
2978 {
2979 return g_ventoy_iso_raw ? 0 : 1;
2980 }
2981 else if (args[0][0] == '2')
2982 {
2983 return g_ventoy_iso_uefi_drv ? 0 : 1;
2984 }
2985
2986 return 1;
2987 }
2988
2989 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2990 {
2991 static int configfile_mode = 0;
2992 char memfile[128] = {0};
2993
2994 (void)ctxt;
2995 (void)argc;
2996 (void)args;
2997
2998 /*
2999 * args[0]: 0:normal 1:configfile
3000 * args[1]: 0:list_buf 1:tree_buf
3001 */
3002
3003 if (argc != 2)
3004 {
3005 debug("Invalid argc %d\n", argc);
3006 return 0;
3007 }
3008
3009 if (args[0][0] == '0')
3010 {
3011 if (args[1][0] == '0')
3012 {
3013 grub_script_execute_sourcecode(g_list_script_buf);
3014 }
3015 else
3016 {
3017 grub_script_execute_sourcecode(g_tree_script_buf);
3018 }
3019 }
3020 else
3021 {
3022 if (configfile_mode)
3023 {
3024 debug("Now already in F3 mode %d\n", configfile_mode);
3025 return 0;
3026 }
3027
3028 if (args[1][0] == '0')
3029 {
3030 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3031 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3032 }
3033 else
3034 {
3035 g_ventoy_last_entry = -1;
3036 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3037 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3038 }
3039
3040 configfile_mode = 1;
3041 grub_script_execute_sourcecode(memfile);
3042 configfile_mode = 0;
3043 }
3044
3045 return 0;
3046 }
3047
3048 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3049 {
3050 grub_file_t file;
3051
3052 (void)ctxt;
3053
3054 if (argc != 1)
3055 {
3056 return 1;
3057 }
3058
3059 g_ventoy_case_insensitive = 1;
3060 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3061 g_ventoy_case_insensitive = 0;
3062
3063 grub_errno = 0;
3064
3065 if (file)
3066 {
3067 grub_file_close(file);
3068 return 0;
3069 }
3070 return 1;
3071 }
3072
3073 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3074 {
3075 int id = 0;
3076 int find = 0;
3077 grub_disk_t disk;
3078 const char *isopath = NULL;
3079 char hdname[32];
3080 ventoy_mbr_head mbr;
3081
3082 (void)ctxt;
3083 (void)argc;
3084
3085 if (argc != 1)
3086 {
3087 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3088 }
3089
3090 isopath = grub_env_get("vtoy_iso_part");
3091 if (!isopath)
3092 {
3093 debug("isopath is null %p\n", isopath);
3094 return 0;
3095 }
3096
3097 debug("isopath is %s\n", isopath);
3098
3099 for (id = 0; id < 30 && (find == 0); id++)
3100 {
3101 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3102 if (grub_strstr(isopath, hdname))
3103 {
3104 debug("skip %s ...\n", hdname);
3105 continue;
3106 }
3107
3108 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3109
3110 disk = grub_disk_open(hdname);
3111 if (!disk)
3112 {
3113 debug("%s not exist\n", hdname);
3114 break;
3115 }
3116
3117 grub_memset(&mbr, 0, sizeof(mbr));
3118 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3119 {
3120 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3121 {
3122 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3123 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3124 {
3125
3126 grub_env_set(args[0], hdname);
3127 find = 1;
3128 }
3129 }
3130 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3131 }
3132 else
3133 {
3134 debug("read %s failed\n", hdname);
3135 }
3136
3137 grub_disk_close(disk);
3138 }
3139
3140 return 0;
3141 }
3142
3143 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3144 {
3145 int len = 1024;
3146 grub_file_t file;
3147 char *buf = NULL;
3148
3149 (void)ctxt;
3150 (void)argc;
3151
3152 if (argc != 2)
3153 {
3154 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3155 }
3156
3157 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3158 if (!file)
3159 {
3160 debug("failed to open file %s\n", args[0]);
3161 return 0;
3162 }
3163
3164 buf = grub_malloc(len);
3165 if (!buf)
3166 {
3167 goto end;
3168 }
3169
3170 buf[len - 1] = 0;
3171 grub_file_read(file, buf, len - 1);
3172
3173 ventoy_get_line(buf);
3174 ventoy_set_env(args[1], buf);
3175
3176 end:
3177
3178 grub_check_free(buf);
3179 grub_file_close(file);
3180
3181 return 0;
3182 }
3183
3184 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3185 {
3186 (void)disk;
3187 (void)data;
3188
3189 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3190 "0 %llu linear /dev/ventoy %llu\n",
3191 (ulonglong)partition->len, (ulonglong)partition->start);
3192
3193 return 0;
3194 }
3195
3196 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3197 {
3198 char *device_name = NULL;
3199 grub_device_t dev = NULL;
3200 char buf[64];
3201
3202 (void)ctxt;
3203
3204 g_part_list_pos = 0;
3205 grub_env_unset("vtoy_img_part_file");
3206
3207 if (argc != 1)
3208 {
3209 return 1;
3210 }
3211
3212 device_name = grub_file_get_device_name(args[0]);
3213 if (!device_name)
3214 {
3215 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3216 goto end;
3217 }
3218
3219 dev = grub_device_open(device_name);
3220 if (!dev)
3221 {
3222 debug("grub_device_open failed, %s\n", device_name);
3223 goto end;
3224 }
3225
3226 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3227
3228 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3229 grub_env_set("vtoy_img_part_file", buf);
3230
3231 end:
3232
3233 check_free(device_name, grub_free);
3234 check_free(dev, grub_device_close);
3235
3236 return 0;
3237 }
3238
3239
3240 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3241 {
3242 int rc = 1;
3243 grub_file_t file;
3244 char *buf = NULL;
3245
3246 (void)ctxt;
3247 (void)argc;
3248
3249 if (argc != 2)
3250 {
3251 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3252 }
3253
3254 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3255 if (!file)
3256 {
3257 debug("failed to open file %s\n", args[0]);
3258 return 1;
3259 }
3260
3261 buf = grub_malloc(file->size + 1);
3262 if (!buf)
3263 {
3264 goto end;
3265 }
3266
3267 buf[file->size] = 0;
3268 grub_file_read(file, buf, file->size);
3269
3270 if (grub_strstr(buf, args[1]))
3271 {
3272 rc = 0;
3273 }
3274
3275 end:
3276
3277 grub_check_free(buf);
3278 grub_file_close(file);
3279
3280 return rc;
3281 }
3282
3283 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3284 {
3285 int len;
3286 grub_file_t file;
3287 char buf[64];
3288 grub_uint64_t size;
3289 ventoy_iso9660_vd pvd;
3290
3291 (void)ctxt;
3292 (void)argc;
3293
3294 if (argc != 4)
3295 {
3296 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3297 }
3298
3299 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3300 if (!file)
3301 {
3302 debug("failed to open file %s\n", args[0]);
3303 return 0;
3304 }
3305
3306 grub_file_seek(file, 16 * 2048);
3307 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3308 if (len != sizeof(pvd))
3309 {
3310 debug("failed to read pvd %d\n", len);
3311 goto end;
3312 }
3313
3314 grub_memset(buf, 0, sizeof(buf));
3315 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3316 ventoy_set_env(args[1], buf);
3317
3318 grub_memset(buf, 0, sizeof(buf));
3319 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3320 ventoy_set_env(args[2], buf);
3321
3322 size = pvd.space;
3323 size *= 2048;
3324 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3325 ventoy_set_env(args[3], buf);
3326
3327 end:
3328 grub_file_close(file);
3329
3330 return 0;
3331 }
3332
3333 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3334 {
3335 int len;
3336 grub_file_t file;
3337 char buf[64];
3338
3339 (void)ctxt;
3340 (void)argc;
3341
3342 if (argc != 2)
3343 {
3344 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3345 }
3346
3347 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3348 if (!file)
3349 {
3350 debug("failed to open file %s\n", args[0]);
3351 return 0;
3352 }
3353
3354 grub_memset(buf, 0, sizeof(buf));
3355 grub_file_seek(file, 16 * 2048 + 813);
3356 len = (int)grub_file_read(file, buf, 17);
3357 if (len != 17)
3358 {
3359 debug("failed to read create date %d\n", len);
3360 goto end;
3361 }
3362
3363 ventoy_set_env(args[1], buf);
3364
3365 end:
3366 grub_file_close(file);
3367
3368 return 0;
3369 }
3370
3371 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3372 {
3373 (void)ctxt;
3374 (void)argc;
3375 (void)args;
3376
3377 ventoy_env_hook_root(1);
3378
3379 return 0;
3380 }
3381
3382 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3383 {
3384 (void)ctxt;
3385 (void)argc;
3386 (void)args;
3387
3388 ventoy_env_hook_root(0);
3389
3390 return 0;
3391 }
3392
3393 #ifdef GRUB_MACHINE_EFI
3394 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3395 {
3396 int ret = 1;
3397 grub_uint8_t *var;
3398 grub_size_t size;
3399 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3400
3401 (void)ctxt;
3402 (void)argc;
3403 (void)args;
3404
3405 var = grub_efi_get_variable("SecureBoot", &global, &size);
3406 if (var && *var == 1)
3407 {
3408 return 0;
3409 }
3410
3411 return ret;
3412 }
3413 #else
3414 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3415 {
3416 (void)ctxt;
3417 (void)argc;
3418 (void)args;
3419 return 1;
3420 }
3421 #endif
3422
3423 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3424 {
3425 int i;
3426 int buflen;
3427 int datalen;
3428 int loclen;
3429 int img_chunk_num;
3430 int image_sector_size;
3431 char cmd[64];
3432 ventoy_chain_head *chain;
3433 ventoy_img_chunk *chunk;
3434 ventoy_os_param *osparam;
3435 ventoy_image_location *location;
3436 ventoy_image_disk_region *region;
3437 struct grub_acpi_table_header *acpi;
3438
3439 (void)ctxt;
3440
3441 if (argc != 2)
3442 {
3443 return 1;
3444 }
3445
3446 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3447
3448 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3449 if (!chain)
3450 {
3451 return 1;
3452 }
3453
3454 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3455
3456 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3457 {
3458 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3459 return 1;
3460 }
3461
3462 img_chunk_num = chain->img_chunk_num;
3463
3464 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3465 datalen = sizeof(ventoy_os_param) + loclen;
3466
3467 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3468 acpi = grub_zalloc(buflen);
3469 if (!acpi)
3470 {
3471 return 1;
3472 }
3473
3474 /* Step1: Fill acpi table header */
3475 grub_memcpy(acpi->signature, "VTOY", 4);
3476 acpi->length = buflen;
3477 acpi->revision = 1;
3478 grub_memcpy(acpi->oemid, "VENTOY", 6);
3479 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3480 acpi->oemrev = 1;
3481 acpi->creator_id[0] = 1;
3482 acpi->creator_rev = 1;
3483
3484 /* Step2: Fill data */
3485 osparam = (ventoy_os_param *)(acpi + 1);
3486 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3487 osparam->vtoy_img_location_addr = 0;
3488 osparam->vtoy_img_location_len = loclen;
3489 osparam->chksum = 0;
3490 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3491
3492 location = (ventoy_image_location *)(osparam + 1);
3493 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3494 location->image_sector_size = image_sector_size;
3495 location->disk_sector_size = chain->disk_sector_size;
3496 location->region_count = img_chunk_num;
3497
3498 region = location->regions;
3499 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3500 if (512 == image_sector_size)
3501 {
3502 for (i = 0; i < img_chunk_num; i++)
3503 {
3504 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3505 region->image_start_sector = chunk->img_start_sector * 4;
3506 region->disk_start_sector = chunk->disk_start_sector;
3507 region++;
3508 chunk++;
3509 }
3510 }
3511 else
3512 {
3513 for (i = 0; i < img_chunk_num; i++)
3514 {
3515 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3516 region->image_start_sector = chunk->img_start_sector;
3517 region->disk_start_sector = chunk->disk_start_sector;
3518 region++;
3519 chunk++;
3520 }
3521 }
3522
3523 /* Step3: Fill acpi checksum */
3524 acpi->checksum = 0;
3525 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3526
3527 /* load acpi table */
3528 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3529 grub_script_execute_sourcecode(cmd);
3530
3531 grub_free(acpi);
3532
3533 VENTOY_CMD_RETURN(0);
3534 }
3535
3536 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3537 {
3538 (void)ctxt;
3539 (void)argc;
3540 (void)args;
3541
3542 g_ventoy_last_entry_back = g_ventoy_last_entry;
3543 g_ventoy_last_entry = -1;
3544
3545 return 0;
3546 }
3547
3548 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3549 {
3550 (void)ctxt;
3551 (void)argc;
3552 (void)args;
3553
3554 g_ventoy_last_entry = g_ventoy_last_entry_back;
3555
3556 return 0;
3557 }
3558
3559 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3560 {
3561 grub_uint64_t sectors;
3562
3563 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3564 {
3565 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3566 }
3567 else
3568 {
3569 sectors = gpt->MBR.PartTbl[0].SectorCount;
3570 }
3571
3572 return sectors * 512;
3573 }
3574
3575 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3576 {
3577 const char *pos = filename + 1;
3578
3579 if (info->dir)
3580 {
3581 while (*pos)
3582 {
3583 if (*pos == '.')
3584 {
3585 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3586 {
3587 grub_strncpy((char *)data, filename, 128);
3588 return 1;
3589 }
3590 }
3591 pos++;
3592 }
3593 }
3594
3595 return 0;
3596 }
3597
3598 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3599 {
3600 int rc = 1;
3601 char *device_name = NULL;
3602 grub_device_t dev = NULL;
3603 grub_fs_t fs = NULL;
3604 char buf[128] = {0};
3605
3606 (void)ctxt;
3607
3608 if (argc != 3)
3609 {
3610 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3611 return 1;
3612 }
3613
3614 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3615
3616 device_name = grub_file_get_device_name(args[0]);
3617 if (!device_name)
3618 {
3619 debug("grub_file_get_device_name failed, %s\n", args[0]);
3620 goto end;
3621 }
3622
3623 dev = grub_device_open(device_name);
3624 if (!dev)
3625 {
3626 debug("grub_device_open failed, %s\n", device_name);
3627 goto end;
3628 }
3629
3630 fs = grub_fs_probe(dev);
3631 if (!fs)
3632 {
3633 debug("grub_fs_probe failed, %s\n", device_name);
3634 goto end;
3635 }
3636
3637 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3638
3639 if (buf[0])
3640 {
3641 ventoy_set_env(args[2], buf);
3642 }
3643
3644 rc = 0;
3645
3646 end:
3647
3648 check_free(device_name, grub_free);
3649 check_free(dev, grub_device_close);
3650
3651 return rc;
3652 }
3653
3654 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3655 {
3656 char name[64];
3657 int ret;
3658 grub_disk_t disk;
3659 grub_device_t dev;
3660
3661 (void)argc;
3662 (void)ctxt;
3663
3664 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3665 if (!g_ventoy_part_info)
3666 {
3667 return 1;
3668 }
3669
3670 disk = grub_disk_open(args[0]);
3671 if (!disk)
3672 {
3673 debug("Failed to open disk %s\n", args[0]);
3674 return 1;
3675 }
3676
3677 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3678
3679 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3680 grub_disk_close(disk);
3681
3682 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3683 dev = grub_device_open(name);
3684 if (dev)
3685 {
3686 /* make sure that we are running in a correct Ventoy device */
3687 ret = ventoy_check_device(dev);
3688 grub_device_close(dev);
3689
3690 if (ret)
3691 {
3692 grub_exit();
3693 }
3694 }
3695
3696 return 0;
3697 }
3698
3699 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
3700 {
3701 int ret = 1;
3702 const char *vcfg = NULL;
3703
3704 (void)argc;
3705 (void)ctxt;
3706
3707 vcfg = ventoy_plugin_get_custom_boot(args[0]);
3708 if (vcfg)
3709 {
3710 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
3711 grub_env_set(args[1], vcfg);
3712 ret = 0;
3713 }
3714 else
3715 {
3716 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
3717 }
3718
3719 grub_errno = 0;
3720 return ret;
3721 }
3722
3723
3724 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3725 {
3726 int id;
3727 grub_uint8_t zeroguid[16] = {0};
3728
3729 (void)argc;
3730 (void)ctxt;
3731
3732 id = (int)grub_strtoul(args[0], NULL, 10);
3733 grub_errno = 0;
3734
3735 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3736 {
3737 if (id >= 1 && id <= 128)
3738 {
3739 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3740 {
3741 return 0;
3742 }
3743 }
3744 }
3745 else
3746 {
3747 if (id >= 1 && id <= 4)
3748 {
3749 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3750 {
3751 return 0;
3752 }
3753 }
3754 }
3755
3756 return 1;
3757 }
3758
3759 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3760 {
3761 int rc = 1;
3762 char *device_name = NULL;
3763 grub_device_t dev = NULL;
3764 grub_fs_t fs = NULL;
3765 char *label = NULL;
3766
3767 (void)ctxt;
3768
3769 if (argc != 2)
3770 {
3771 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3772 return 1;
3773 }
3774
3775 device_name = grub_file_get_device_name(args[0]);
3776 if (!device_name)
3777 {
3778 debug("grub_file_get_device_name failed, %s\n", args[0]);
3779 goto end;
3780 }
3781
3782 dev = grub_device_open(device_name);
3783 if (!dev)
3784 {
3785 debug("grub_device_open failed, %s\n", device_name);
3786 goto end;
3787 }
3788
3789 fs = grub_fs_probe(dev);
3790 if (!fs)
3791 {
3792 debug("grub_fs_probe failed, %s\n", device_name);
3793 goto end;
3794 }
3795
3796 fs->fs_label(dev, &label);
3797 if (label)
3798 {
3799 ventoy_set_env(args[1], label);
3800 grub_free(label);
3801 }
3802
3803 rc = 0;
3804
3805 end:
3806
3807 check_free(device_name, grub_free);
3808 check_free(dev, grub_device_close);
3809
3810 return rc;
3811 }
3812
3813 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3814 {
3815 if (!info->dir)
3816 {
3817 grub_snprintf((char *)data, 256, "%s", filename);
3818 return 1;
3819 }
3820
3821 return 0;
3822 }
3823
3824
3825 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3826 {
3827 int rc = 1;
3828 char *device_name = NULL;
3829 grub_device_t dev = NULL;
3830 grub_fs_t fs = NULL;
3831 char name[256] ={0};
3832
3833 (void)ctxt;
3834
3835 if (argc != 3)
3836 {
3837 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3838 return 1;
3839 }
3840
3841 device_name = grub_file_get_device_name(args[0]);
3842 if (!device_name)
3843 {
3844 debug("grub_file_get_device_name failed, %s\n", args[0]);
3845 goto end;
3846 }
3847
3848 dev = grub_device_open(device_name);
3849 if (!dev)
3850 {
3851 debug("grub_device_open failed, %s\n", device_name);
3852 goto end;
3853 }
3854
3855 fs = grub_fs_probe(dev);
3856 if (!fs)
3857 {
3858 debug("grub_fs_probe failed, %s\n", device_name);
3859 goto end;
3860 }
3861
3862 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3863 if (name[0])
3864 {
3865 ventoy_set_env(args[2], name);
3866 }
3867
3868 rc = 0;
3869
3870 end:
3871
3872 check_free(device_name, grub_free);
3873 check_free(dev, grub_device_close);
3874
3875 return rc;
3876 }
3877
3878 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3879 {
3880 char c;
3881 char *pos = NULL;
3882 char *end = NULL;
3883
3884 (void)ctxt;
3885
3886 if (argc != 2)
3887 {
3888 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3889 return 1;
3890 }
3891
3892 for (pos = args[0]; *pos; pos++)
3893 {
3894 if (*pos == '.')
3895 {
3896 end = pos;
3897 }
3898 }
3899
3900 if (end)
3901 {
3902 c = *end;
3903 *end = 0;
3904 }
3905
3906 grub_env_set(args[1], args[0]);
3907
3908 if (end)
3909 {
3910 *end = c;
3911 }
3912
3913 return 0;
3914 }
3915
3916 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
3917 {
3918 int i;
3919 int len;
3920 const char *buf;
3921
3922 (void)ctxt;
3923
3924 if (argc != 2)
3925 {
3926 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
3927 return 1;
3928 }
3929
3930 buf = args[0];
3931 len = (int)grub_strlen(buf);
3932 for (i = len; i > 0; i--)
3933 {
3934 if (buf[i - 1] == '/')
3935 {
3936 grub_env_set(args[1], buf + i);
3937 return 0;
3938 }
3939 }
3940
3941 grub_env_set(args[1], buf);
3942
3943 return 0;
3944 }
3945
3946 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3947 {
3948 struct grub_video_mode_info info;
3949 char buf[32];
3950
3951 (void)ctxt;
3952 (void)argc;
3953 (void)args;
3954
3955 if (!g_video_mode_list)
3956 {
3957 ventoy_enum_video_mode();
3958 }
3959
3960 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3961 {
3962 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3963 }
3964 else
3965 {
3966 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3967 }
3968
3969 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3970
3971 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3972 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3973
3974 VENTOY_CMD_RETURN(0);
3975 }
3976
3977 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3978 {
3979 struct grub_video_mode_info info;
3980 char buf[32];
3981
3982 (void)ctxt;
3983 (void)argc;
3984 (void)args;
3985
3986 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3987 {
3988 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
3989 }
3990 else
3991 {
3992 grub_snprintf(buf, sizeof(buf), "0x0x0");
3993 }
3994
3995 grub_env_set(args[0], buf);
3996
3997 VENTOY_CMD_RETURN(0);
3998 }
3999
4000 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4001 {
4002 int id;
4003 char buf[32];
4004
4005 (void)ctxt;
4006 (void)argc;
4007
4008 if (!g_video_mode_list)
4009 {
4010 return 0;
4011 }
4012
4013 id = (int)grub_strtoul(args[0], NULL, 10);
4014 if (id < g_video_mode_num)
4015 {
4016 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4017 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4018 }
4019
4020 grub_env_set(args[1], buf);
4021
4022 VENTOY_CMD_RETURN(0);
4023 }
4024
4025 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
4026 {
4027 grub_uint64_t size = 0;
4028 grub_file_t file;
4029 va_list ap;
4030 char fullpath[256] = {0};
4031
4032 va_start (ap, fmt);
4033 grub_vsnprintf(fullpath, 255, fmt, ap);
4034 va_end (ap);
4035
4036 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
4037 if (!file)
4038 {
4039 debug("grub_file_open failed <%s>\n", fullpath);
4040 grub_errno = 0;
4041 return 0;
4042 }
4043
4044 size = file->size;
4045 grub_file_close(file);
4046 return size;
4047 }
4048
4049 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
4050 {
4051 va_list ap;
4052 grub_file_t file;
4053 char fullpath[256] = {0};
4054
4055 va_start (ap, fmt);
4056 grub_vsnprintf(fullpath, 255, fmt, ap);
4057 va_end (ap);
4058
4059 file = grub_file_open(fullpath, type);
4060 if (!file)
4061 {
4062 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
4063 grub_errno = 0;
4064 }
4065
4066 return file;
4067 }
4068
4069 int ventoy_is_file_exist(const char *fmt, ...)
4070 {
4071 va_list ap;
4072 int len;
4073 char *pos = NULL;
4074 char buf[256] = {0};
4075
4076 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
4077 pos = buf + 6;
4078
4079 va_start (ap, fmt);
4080 len = grub_vsnprintf(pos, 255, fmt, ap);
4081 va_end (ap);
4082
4083 grub_strncpy(pos + len, "\" ]", 3);
4084
4085 debug("script exec %s\n", buf);
4086
4087 if (0 == grub_script_execute_sourcecode(buf))
4088 {
4089 return 1;
4090 }
4091
4092 return 0;
4093 }
4094
4095 int ventoy_is_dir_exist(const char *fmt, ...)
4096 {
4097 va_list ap;
4098 int len;
4099 char *pos = NULL;
4100 char buf[256] = {0};
4101
4102 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
4103 pos = buf + 6;
4104
4105 va_start (ap, fmt);
4106 len = grub_vsnprintf(pos, 255, fmt, ap);
4107 va_end (ap);
4108
4109 grub_strncpy(pos + len, "\" ]", 3);
4110
4111 debug("script exec %s\n", buf);
4112
4113 if (0 == grub_script_execute_sourcecode(buf))
4114 {
4115 return 1;
4116 }
4117
4118 return 0;
4119 }
4120
4121 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
4122 {
4123 mz_stream s;
4124 grub_uint8_t *outbuf;
4125 grub_uint8_t gzHdr[10] =
4126 {
4127 0x1F, 0x8B, /* magic */
4128 8, /* z method */
4129 0, /* flags */
4130 0,0,0,0, /* mtime */
4131 4, /* xfl */
4132 3, /* OS */
4133 };
4134
4135 grub_memset(&s, 0, sizeof(mz_stream));
4136
4137 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
4138
4139 outbuf = (grub_uint8_t *)mem_out;
4140
4141 mem_out_len -= sizeof(gzHdr) + 8;
4142 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
4143 outbuf += sizeof(gzHdr);
4144
4145 s.avail_in = mem_in_len;
4146 s.next_in = mem_in;
4147
4148 s.avail_out = mem_out_len;
4149 s.next_out = outbuf;
4150
4151 mz_deflate(&s, MZ_FINISH);
4152
4153 mz_deflateEnd(&s);
4154
4155 outbuf += s.total_out;
4156 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4157 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4158
4159 return s.total_out + sizeof(gzHdr) + 8;
4160 }
4161
4162 static int ventoy_env_init(void)
4163 {
4164 char buf[64];
4165
4166 grub_env_set("vtdebug_flag", "");
4167
4168 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4169 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4170 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4171 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4172
4173 ventoy_filt_register(0, ventoy_wrapper_open);
4174
4175 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4176 if (g_grub_param)
4177 {
4178 g_grub_param->grub_env_get = grub_env_get;
4179 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4180 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4181 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4182 grub_env_set("env_param", buf);
4183 grub_env_set("ventoy_env_param", buf);
4184 grub_env_export("ventoy_env_param");
4185 }
4186
4187 return 0;
4188 }
4189
4190 static cmd_para ventoy_cmds[] =
4191 {
4192 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4193 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4194 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4195 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4196 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4197 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4198 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4199 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4200 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4201 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4202 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4203 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4204 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4205 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4206 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4207 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4208 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4209 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4210 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4211 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4212 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4213 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4214 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4215
4216 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4217 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4218 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4219 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4220 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4221 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4222 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4223
4224 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4225 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4226 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4227 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4228 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4229 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4230 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4231 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4232 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4233
4234
4235 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4236 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4237 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4238 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4239 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4240 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4241 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4242 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4243 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4244 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4245 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4246
4247 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4248 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4249 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4250 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4251 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4252 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4253
4254 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4255 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4256 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4257 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4258 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4259 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4260 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4261 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4262 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4263 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4264
4265 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4266 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4267 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4268 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4269 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4270 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4271 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4272 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4273
4274 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4275 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4276 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4277
4278
4279 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4280 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4281 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4282
4283 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4284 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4285 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4286
4287
4288 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4289 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4290 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4291 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4292 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4293 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4294 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4295 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4296 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4297 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4298
4299 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4300 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4301 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4302 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4303
4304 };
4305
4306
4307
4308 GRUB_MOD_INIT(ventoy)
4309 {
4310 grub_uint32_t i;
4311 cmd_para *cur = NULL;
4312
4313 ventoy_env_init();
4314
4315 ventoy_arch_mode_init();
4316
4317 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4318 {
4319 cur = ventoy_cmds + i;
4320 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4321 cur->summary, cur->description, cur->parser);
4322 }
4323 }
4324
4325 GRUB_MOD_FINI(ventoy)
4326 {
4327 grub_uint32_t i;
4328
4329 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4330 {
4331 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4332 }
4333 }
4334