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