]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
Display warning message if ISO file has an invalid size.
[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_colect_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
1285 {
1286 return 0;
1287 }
1288
1289 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1290 {
1291 return 0;
1292 }
1293
1294 if (g_plugin_image_list)
1295 {
1296 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1297 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1298 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1299 {
1300 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1301 return 0;
1302 }
1303 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
1304 {
1305 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf);
1306 return 0;
1307 }
1308 }
1309
1310 img = grub_zalloc(sizeof(img_info));
1311 if (img)
1312 {
1313 img->type = type;
1314 img->plugin_list_index = index;
1315 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1316
1317 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1318
1319 img->size = info->size;
1320 if (0 == img->size)
1321 {
1322 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1323 }
1324
1325 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1326 {
1327 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1328 grub_free(img);
1329 return 0;
1330 }
1331
1332 if (g_ventoy_img_list)
1333 {
1334 tail = *(node->tail);
1335 img->prev = tail;
1336 tail->next = img;
1337 }
1338 else
1339 {
1340 g_ventoy_img_list = img;
1341 }
1342
1343 img->id = g_ventoy_img_count;
1344 img->parent = node;
1345 if (node && NULL == node->firstiso)
1346 {
1347 node->firstiso = img;
1348 }
1349
1350 node->isocnt++;
1351 tmp = node->parent;
1352 while (tmp)
1353 {
1354 tmp->isocnt++;
1355 tmp = tmp->parent;
1356 }
1357
1358 *((img_info **)(node->tail)) = img;
1359 g_ventoy_img_count++;
1360
1361 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1362 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1363 if (!img->class)
1364 {
1365 img->class = g_menu_class[type];
1366 }
1367 img->menu_prefix = g_menu_prefix[type];
1368
1369 if (img_type_iso == type)
1370 {
1371 if (ventoy_plugin_check_memdisk(img->path))
1372 {
1373 img->menu_prefix = "miso";
1374 }
1375 }
1376
1377 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1378 }
1379 }
1380
1381 return 0;
1382 }
1383
1384 static int ventoy_arch_mode_init(void)
1385 {
1386 #ifdef GRUB_MACHINE_EFI
1387 if (grub_strcmp(GRUB_TARGET_CPU, "i386") == 0)
1388 {
1389 g_ventoy_plat_data = VTOY_PLAT_I386_UEFI;
1390 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "ia32");
1391 }
1392 else if (grub_strcmp(GRUB_TARGET_CPU, "arm64") == 0)
1393 {
1394 g_ventoy_plat_data = VTOY_PLAT_ARM64_UEFI;
1395 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "aa64");
1396 }
1397 else
1398 {
1399 g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI;
1400 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi");
1401 }
1402 #else
1403 g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY;
1404 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy");
1405 #endif
1406
1407 return 0;
1408 }
1409
1410 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1411 {
1412 int len = GRUB_UINT_MAX;
1413 const char *value = NULL;
1414 char name[32] = {0};
1415 char plat[32] = {0};
1416 char guidstr[32] = {0};
1417 ventoy_guid guid = VENTOY_GUID;
1418 const char *fmt1 = NULL;
1419 const char *fmt2 = NULL;
1420 const char *fmt3 = NULL;
1421 grub_uint32_t *puint = (grub_uint32_t *)name;
1422 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1423 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1424 const char fmtcode[]={
1425 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1426 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1427 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1428 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1429 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1430 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1431 };
1432
1433 grub_memset(name, 0, sizeof(name));
1434 puint[0] = grub_swap_bytes32(0x56454e54);
1435 puint[3] = grub_swap_bytes32(0x4f4e0000);
1436 puint[2] = grub_swap_bytes32(0x45525349);
1437 puint[1] = grub_swap_bytes32(0x4f595f56);
1438 value = ventoy_get_env(name);
1439
1440 grub_memset(name, 0, sizeof(name));
1441 puint[1] = grub_swap_bytes32(0x5f544f50);
1442 puint[0] = grub_swap_bytes32(0x56544c45);
1443 fmt1 = ventoy_get_env(name);
1444 if (!fmt1)
1445 {
1446 fmt1 = fmtdata;
1447 }
1448
1449 grub_memset(name, 0, sizeof(name));
1450 puint[1] = grub_swap_bytes32(0x5f4c4654);
1451 puint[0] = grub_swap_bytes32(0x56544c45);
1452 fmt2 = ventoy_get_env(name);
1453
1454 grub_memset(name, 0, sizeof(name));
1455 puint[1] = grub_swap_bytes32(0x5f434c52);
1456 puint[0] = grub_swap_bytes32(0x56544c45);
1457 fmt3 = ventoy_get_env(name);
1458
1459 grub_memcpy(guidstr, &guid, sizeof(guid));
1460
1461 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1462
1463 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1464 #pragma GCC diagnostic push
1465 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1466 len = grub_snprintf(buffer, buflen, fmtcode,
1467 fmt1 ? fmt1 : fmtdata,
1468 fmt2 ? fmt2 : fmtdata + 4,
1469 value ? value : "", plat, guidstr,
1470 fmt3 ? fmt3 : fmtdata + 6);
1471 #pragma GCC diagnostic pop
1472
1473 grub_memset(name, 0, sizeof(name));
1474 puint[0] = grub_swap_bytes32(0x76746f79);
1475 puint[2] = grub_swap_bytes32(0x656e7365);
1476 puint[1] = grub_swap_bytes32(0x5f6c6963);
1477 ventoy_set_env(name, guidstr);
1478
1479 return len;
1480 }
1481
1482 int ventoy_check_password(const vtoy_password *pwd, int retry)
1483 {
1484 int offset;
1485 char input[256];
1486 grub_uint8_t md5[16];
1487
1488 while (retry--)
1489 {
1490 grub_memset(input, 0, sizeof(input));
1491
1492 grub_printf("Enter password: ");
1493 grub_refresh();
1494
1495 if (pwd->type == VTOY_PASSWORD_TXT)
1496 {
1497 grub_password_get(input, 128);
1498 if (grub_strcmp(pwd->text, input) == 0)
1499 {
1500 return 0;
1501 }
1502 }
1503 else if (pwd->type == VTOY_PASSWORD_MD5)
1504 {
1505 grub_password_get(input, 128);
1506 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1507 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1508 {
1509 return 0;
1510 }
1511 }
1512 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1513 {
1514 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1515 grub_password_get(input + offset, 128);
1516
1517 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1518 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1519 {
1520 return 0;
1521 }
1522 }
1523
1524 grub_printf("Invalid password!\n\n");
1525 grub_refresh();
1526 }
1527
1528 return 1;
1529 }
1530
1531 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1532 {
1533 img_info *minimg = NULL;
1534 img_info *img = (img_info *)(node->firstiso);
1535
1536 while (img && (img_iterator_node *)(img->parent) == node)
1537 {
1538 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1539 {
1540 minimg = img;
1541 }
1542 img = img->next;
1543 }
1544
1545 if (minimg)
1546 {
1547 minimg->select = 1;
1548 }
1549
1550 return minimg;
1551 }
1552
1553 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1554 {
1555 img_iterator_node *Minchild = NULL;
1556 img_iterator_node *child = node->firstchild;
1557
1558 while (child && child->parent == node)
1559 {
1560 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1561 {
1562 Minchild = child;
1563 }
1564 child = child->next;
1565 }
1566
1567 if (Minchild)
1568 {
1569 Minchild->select = 1;
1570 }
1571
1572 return Minchild;
1573 }
1574
1575 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1576 {
1577 int offset = 1;
1578 img_info *img = NULL;
1579 const char *dir_class = NULL;
1580 const char *dir_alias = NULL;
1581 img_iterator_node *child = NULL;
1582
1583 if (node->isocnt == 0 || node->done == 1)
1584 {
1585 return 0;
1586 }
1587
1588 if (node->parent && node->parent->dirlen < node->dirlen)
1589 {
1590 offset = node->parent->dirlen;
1591 }
1592
1593 if (node == &g_img_iterator_head)
1594 {
1595 if (g_default_menu_mode == 0)
1596 {
1597 if (g_tree_view_menu_style == 0)
1598 {
1599 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1600 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1601 " echo 'return ...' \n"
1602 "}\n", "<--");
1603 }
1604 else
1605 {
1606 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1607 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1608 " echo '%s ...' \n"
1609 "}\n", "return");
1610 }
1611 }
1612 }
1613 else
1614 {
1615 node->dir[node->dirlen - 1] = 0;
1616 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1617 if (!dir_class)
1618 {
1619 dir_class = "vtoydir";
1620 }
1621
1622 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1623 if (dir_alias)
1624 {
1625 if (g_tree_view_menu_style == 0)
1626 {
1627 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1628 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1629 "DIR", dir_alias, dir_class, node->dir + offset);
1630 }
1631 else
1632 {
1633 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1634 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1635 dir_alias, dir_class, node->dir + offset);
1636 }
1637 }
1638 else
1639 {
1640 dir_alias = node->dir + offset;
1641
1642 if (g_tree_view_menu_style == 0)
1643 {
1644 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1645 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1646 "DIR", dir_alias, dir_class, node->dir + offset);
1647 }
1648 else
1649 {
1650 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1651 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1652 dir_alias, dir_class, node->dir + offset);
1653 }
1654 }
1655
1656 if (g_tree_view_menu_style == 0)
1657 {
1658 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1659 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1660 " echo 'return ...' \n"
1661 "}\n", "<--");
1662 }
1663 else
1664 {
1665 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1666 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1667 " echo '%s ...' \n"
1668 "}\n", "return");
1669 }
1670 }
1671
1672 while ((child = ventoy_get_min_child(node)) != NULL)
1673 {
1674 ventoy_dynamic_tree_menu(child);
1675 }
1676
1677 while ((img = ventoy_get_min_iso(node)) != NULL)
1678 {
1679 if (g_tree_view_menu_style == 0)
1680 {
1681 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1682 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1683 " %s_%s \n"
1684 "}\n",
1685 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1686 img->unsupport ? "[***********] " : "",
1687 img->alias ? img->alias : img->name, img->class, img->id,
1688 img->menu_prefix,
1689 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1690 }
1691 else
1692 {
1693 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1694 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1695 " %s_%s \n"
1696 "}\n",
1697 img->unsupport ? "[***********] " : "",
1698 img->alias ? img->alias : img->name, img->class, img->id,
1699 img->menu_prefix,
1700 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1701 }
1702 }
1703
1704 if (node != &g_img_iterator_head)
1705 {
1706 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1707 }
1708
1709 node->done = 1;
1710 return 0;
1711 }
1712
1713 int ventoy_check_device_result(int ret)
1714 {
1715 char buf[32];
1716
1717 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1718 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1719 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1720
1721 if (ret)
1722 {
1723 grub_printf(VTOY_WARNING"\n");
1724 grub_printf(VTOY_WARNING"\n");
1725 grub_printf(VTOY_WARNING"\n\n\n");
1726
1727 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1728 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1729
1730 grub_printf("\n\nWill exit after 10 seconds ...... ");
1731 grub_refresh();
1732 grub_sleep(10);
1733 }
1734
1735 return ret;
1736 }
1737
1738 int ventoy_check_device(grub_device_t dev)
1739 {
1740 int workaround = 0;
1741 grub_file_t file;
1742 grub_uint64_t offset;
1743 char devname[64];
1744 grub_fs_t fs;
1745 grub_device_t dev2;
1746 char *label = NULL;
1747 struct grub_partition *partition;
1748
1749 if (dev->disk == NULL || dev->disk->partition == NULL)
1750 {
1751 return ventoy_check_device_result(1 | 0x1000);
1752 }
1753
1754 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1755 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1756 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1757 {
1758 #ifndef GRUB_MACHINE_EFI
1759 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
1760 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
1761 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1762 {
1763 return ventoy_check_device_result(2 | 0x1000);
1764 }
1765 else
1766 {
1767 workaround = 1;
1768 }
1769 #endif
1770 }
1771
1772 /* We must have partition 2 */
1773 if (workaround)
1774 {
1775 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1776 }
1777 else
1778 {
1779 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1780 }
1781 if (!file)
1782 {
1783 return ventoy_check_device_result(3 | 0x1000);
1784 }
1785
1786 if (NULL == grub_strstr(file->fs->name, "fat"))
1787 {
1788 grub_file_close(file);
1789 return ventoy_check_device_result(4 | 0x1000);
1790 }
1791
1792 partition = dev->disk->partition;
1793 if (partition->number != 0 || partition->start != 2048)
1794 {
1795 return ventoy_check_device_result(5);
1796 }
1797
1798 if (workaround)
1799 {
1800 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
1801 {
1802 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
1803 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
1804 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
1805 {
1806 grub_file_close(file);
1807 return ventoy_check_device_result(6);
1808 }
1809 }
1810 else
1811 {
1812 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
1813 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
1814 PartTbl[1].SectorCount != 65536)
1815 {
1816 grub_file_close(file);
1817 return ventoy_check_device_result(6);
1818 }
1819 }
1820 }
1821 else
1822 {
1823 offset = partition->start + partition->len;
1824 partition = file->device->disk->partition;
1825 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1826 {
1827 grub_file_close(file);
1828 return ventoy_check_device_result(7);
1829 }
1830 }
1831
1832 grub_file_close(file);
1833
1834 if (workaround == 0)
1835 {
1836 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1837 dev2 = grub_device_open(devname);
1838 if (!dev2)
1839 {
1840 return ventoy_check_device_result(8);
1841 }
1842
1843 fs = grub_fs_probe(dev2);
1844 if (!fs)
1845 {
1846 grub_device_close(dev2);
1847 return ventoy_check_device_result(9);
1848 }
1849
1850 fs->fs_label(dev2, &label);
1851 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1852 {
1853 grub_device_close(dev2);
1854 return ventoy_check_device_result(10);
1855 }
1856
1857 grub_device_close(dev2);
1858 }
1859
1860 return ventoy_check_device_result(0);
1861 }
1862
1863 static int ventoy_set_default_menu(void)
1864 {
1865 int img_len = 0;
1866 char *pos = NULL;
1867 char *end = NULL;
1868 char *def = NULL;
1869 const char *strdata = NULL;
1870 img_info *cur = NULL;
1871 img_info *default_node = NULL;
1872 const char *default_image = NULL;
1873
1874 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1875 if (default_image && default_image[0] == '/')
1876 {
1877 img_len = grub_strlen(default_image);
1878
1879 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1880 {
1881 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1882 {
1883 default_node = cur;
1884 break;
1885 }
1886 }
1887
1888 if (!default_node)
1889 {
1890 return 1;
1891 }
1892
1893 if (0 == g_default_menu_mode)
1894 {
1895 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1896 }
1897 else
1898 {
1899 def = grub_strdup(default_image);
1900 if (!def)
1901 {
1902 return 1;
1903 }
1904
1905 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1906
1907 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1908 if (strdata && strdata[0] == '/')
1909 {
1910 pos = def + grub_strlen(strdata);
1911 if (*pos == '/')
1912 {
1913 pos++;
1914 }
1915 }
1916 else
1917 {
1918 pos = def + 1;
1919 }
1920
1921 while ((end = grub_strchr(pos, '/')) != NULL)
1922 {
1923 *end = 0;
1924 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1925 pos = end + 1;
1926 }
1927
1928 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1929 grub_free(def);
1930 }
1931 }
1932
1933 return 0;
1934 }
1935
1936 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1937 {
1938 int len;
1939 grub_fs_t fs;
1940 grub_device_t dev = NULL;
1941 img_info *cur = NULL;
1942 img_info *tail = NULL;
1943 const char *strdata = NULL;
1944 char *device_name = NULL;
1945 char buf[32];
1946 img_iterator_node *node = NULL;
1947 img_iterator_node *tmp = NULL;
1948
1949 (void)ctxt;
1950
1951 if (argc != 2)
1952 {
1953 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1954 }
1955
1956 if (g_ventoy_img_list || g_ventoy_img_count)
1957 {
1958 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1959 }
1960
1961 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1962 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1963 {
1964 g_filt_dot_underscore_file = 1;
1965 }
1966
1967 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1968 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1969 {
1970 g_sort_case_sensitive = 1;
1971 }
1972
1973 device_name = grub_file_get_device_name(args[0]);
1974 if (!device_name)
1975 {
1976 goto fail;
1977 }
1978
1979 g_enum_dev = dev = grub_device_open(device_name);
1980 if (!dev)
1981 {
1982 goto fail;
1983 }
1984
1985 g_enum_fs = fs = grub_fs_probe(dev);
1986 if (!fs)
1987 {
1988 goto fail;
1989 }
1990
1991 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1992 {
1993 debug("unsupported fs:<%s>\n", fs->name);
1994 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1995 goto fail;
1996 }
1997
1998 ventoy_set_env("vtoy_iso_fs", fs->name);
1999
2000 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2001 if (strdata && strdata[0] == '1')
2002 {
2003 g_default_menu_mode = 1;
2004 }
2005
2006 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2007
2008 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2009
2010 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2011 if (strdata && strdata[0] == '/')
2012 {
2013 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2014 if (g_img_iterator_head.dir[len - 1] != '/')
2015 {
2016 g_img_iterator_head.dir[len++] = '/';
2017 }
2018 g_img_iterator_head.dirlen = len;
2019 }
2020 else
2021 {
2022 g_img_iterator_head.dirlen = 1;
2023 grub_strcpy(g_img_iterator_head.dir, "/");
2024 }
2025
2026 g_img_iterator_head.tail = &tail;
2027
2028 for (node = &g_img_iterator_head; node; node = node->next)
2029 {
2030 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
2031 }
2032
2033 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2034 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2035 {
2036 g_tree_view_menu_style = 1;
2037 }
2038
2039 ventoy_set_default_menu();
2040
2041 for (node = &g_img_iterator_head; node; node = node->next)
2042 {
2043 ventoy_dynamic_tree_menu(node);
2044 }
2045
2046 /* free node */
2047 node = g_img_iterator_head.next;
2048 while (node)
2049 {
2050 tmp = node->next;
2051 grub_free(node);
2052 node = tmp;
2053 }
2054
2055 /* sort image list by image name */
2056 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2057 {
2058 for (tail = cur->next; tail; tail = tail->next)
2059 {
2060 if (ventoy_cmp_img(cur, tail) > 0)
2061 {
2062 ventoy_swap_img(cur, tail);
2063 }
2064 }
2065 }
2066
2067 if (g_default_menu_mode == 1)
2068 {
2069 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2070 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2071 " echo 'return ...' \n"
2072 "}\n", "<--");
2073 }
2074
2075 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2076 {
2077 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2078 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2079 " %s_%s \n"
2080 "}\n",
2081 cur->unsupport ? "[***********] " : "",
2082 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2083 cur->menu_prefix,
2084 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2085 }
2086
2087 g_tree_script_buf[g_tree_script_pos] = 0;
2088 g_list_script_buf[g_list_script_pos] = 0;
2089
2090 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2091 grub_env_set(args[1], buf);
2092
2093 fail:
2094
2095 check_free(device_name, grub_free);
2096 check_free(dev, grub_device_close);
2097
2098 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2099 }
2100
2101
2102 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2103 {
2104 img_info *next = NULL;
2105 img_info *cur = g_ventoy_img_list;
2106
2107 (void)ctxt;
2108 (void)argc;
2109 (void)args;
2110
2111 while (cur)
2112 {
2113 next = cur->next;
2114 grub_free(cur);
2115 cur = next;
2116 }
2117
2118 g_ventoy_img_list = NULL;
2119 g_ventoy_img_count = 0;
2120
2121 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2122 }
2123
2124 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2125 {
2126 long img_id = 0;
2127 img_info *cur = g_ventoy_img_list;
2128
2129 (void)ctxt;
2130
2131 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2132 {
2133 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2134 }
2135
2136 img_id = grub_strtol(args[0], NULL, 10);
2137 if (img_id >= g_ventoy_img_count)
2138 {
2139 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2140 }
2141
2142 debug("Find image %ld name \n", img_id);
2143
2144 while (cur && img_id > 0)
2145 {
2146 img_id--;
2147 cur = cur->next;
2148 }
2149
2150 if (!cur)
2151 {
2152 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2153 }
2154
2155 debug("image name is %s\n", cur->name);
2156
2157 grub_env_set(args[1], cur->name);
2158
2159 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2160 }
2161
2162 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2163 {
2164 int img_id = 0;
2165 char value[32];
2166 char *pos = NULL;
2167 const char *id = NULL;
2168 img_info *cur = g_ventoy_img_list;
2169
2170 (void)ctxt;
2171
2172 if (argc < 1 || argc > 2)
2173 {
2174 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2175 }
2176
2177 id = grub_env_get("chosen");
2178
2179 pos = grub_strstr(id, "VID_");
2180 if (pos)
2181 {
2182 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2183 }
2184 else
2185 {
2186 img_id = (int)grub_strtoul(id, NULL, 10);
2187 }
2188
2189 while (cur)
2190 {
2191 if (img_id == cur->id)
2192 {
2193 break;
2194 }
2195 cur = cur->next;
2196 }
2197
2198 if (!cur)
2199 {
2200 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2201 }
2202
2203 grub_env_set(args[0], cur->path);
2204
2205 if (argc > 1)
2206 {
2207 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2208 grub_env_set(args[1], value);
2209 }
2210
2211 g_svd_replace_offset = 0;
2212
2213 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2214 }
2215
2216 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2217 {
2218 grub_disk_t disk;
2219 char *device_name;
2220 char *pos;
2221 char *pos2;
2222
2223 device_name = grub_file_get_device_name(filename);
2224 if (!device_name)
2225 {
2226 return 1;
2227 }
2228
2229 pos = device_name;
2230 if (pos[0] == '(')
2231 {
2232 pos++;
2233 }
2234
2235 pos2 = grub_strstr(pos, ",");
2236 if (!pos2)
2237 {
2238 pos2 = grub_strstr(pos, ")");
2239 }
2240
2241 if (pos2)
2242 {
2243 *pos2 = 0;
2244 }
2245
2246 disk = grub_disk_open(pos);
2247 if (disk)
2248 {
2249 grub_disk_read(disk, 0, 0x180, 16, guid);
2250 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2251 grub_disk_close(disk);
2252 }
2253 else
2254 {
2255 return 1;
2256 }
2257
2258 grub_free(device_name);
2259 return 0;
2260 }
2261
2262 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2263 {
2264 eltorito_descriptor desc;
2265
2266 grub_memset(&desc, 0, sizeof(desc));
2267 grub_file_seek(file, 17 * 2048);
2268 grub_file_read(file, &desc, sizeof(desc));
2269
2270 if (desc.type != 0 || desc.version != 1)
2271 {
2272 return 0;
2273 }
2274
2275 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2276 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2277 {
2278 return 0;
2279 }
2280
2281 return desc.sector;
2282 }
2283
2284 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2285 {
2286 int i;
2287 int x86count = 0;
2288 grub_uint8_t buf[512];
2289 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2290
2291 grub_file_seek(file, sector * 2048);
2292 grub_file_read(file, buf, sizeof(buf));
2293
2294 if (buf[0] == 0x01 && buf[1] == 0xEF)
2295 {
2296 debug("%s efi eltorito in Validation Entry\n", file->name);
2297 return 1;
2298 }
2299
2300 if (buf[0] == 0x01 && buf[1] == 0x00)
2301 {
2302 x86count++;
2303 }
2304
2305 for (i = 64; i < (int)sizeof(buf); i += 32)
2306 {
2307 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2308 {
2309 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2310 return 1;
2311 }
2312
2313 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2314 {
2315 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2316 return 1;
2317 }
2318 }
2319
2320 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2321 {
2322 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2323 {
2324 if (buf[36] == parttype[i])
2325 {
2326 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2327 return 1;
2328 }
2329 }
2330 }
2331
2332 debug("%s does not contain efi eltorito\n", file->name);
2333 return 0;
2334 }
2335
2336 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2337 {
2338 char *pos;
2339 const char *fs = NULL;
2340 const char *cdprompt = NULL;
2341 grub_uint32_t i;
2342 grub_uint8_t chksum = 0;
2343 grub_disk_t disk;
2344
2345 disk = file->device->disk;
2346 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2347
2348 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2349 param->vtoy_disk_part_id = disk->partition->number + 1;
2350 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2351
2352 pos = grub_strstr(file->name, "/");
2353 if (!pos)
2354 {
2355 pos = file->name;
2356 }
2357
2358 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2359
2360 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2361
2362 param->vtoy_img_size = file->size;
2363
2364 param->vtoy_reserved[0] = g_ventoy_break_level;
2365 param->vtoy_reserved[1] = g_ventoy_debug_level;
2366
2367 param->vtoy_reserved[2] = g_ventoy_chain_type;
2368
2369 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2370 param->vtoy_reserved[4] = 0;
2371 if (g_ventoy_chain_type == 1) /* Windows */
2372 {
2373 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2374 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2375 {
2376 param->vtoy_reserved[4] = 1;
2377 }
2378 }
2379
2380 fs = ventoy_get_env("ventoy_fs_probe");
2381 if (fs && grub_strcmp(fs, "udf") == 0)
2382 {
2383 param->vtoy_reserved[3] = 1;
2384 }
2385
2386 /* calculate checksum */
2387 for (i = 0; i < sizeof(ventoy_os_param); i++)
2388 {
2389 chksum += *((grub_uint8_t *)param + i);
2390 }
2391 param->chksum = (grub_uint8_t)(0x100 - chksum);
2392
2393 return;
2394 }
2395
2396 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2397 {
2398 grub_uint32_t i = 0;
2399 grub_uint64_t total = 0;
2400 ventoy_img_chunk *chunk = NULL;
2401
2402 for (i = 0; i < chunklist->cur_chunk; i++)
2403 {
2404 chunk = chunklist->chunk + i;
2405
2406 if (chunk->disk_start_sector <= start)
2407 {
2408 debug("%u disk start invalid %lu\n", i, (ulong)start);
2409 return 1;
2410 }
2411
2412 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2413 }
2414
2415 if (total != ((file->size + 511) / 512))
2416 {
2417 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2418 return 1;
2419 }
2420
2421 return 0;
2422 }
2423
2424 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2425 {
2426 int fs_type;
2427 int len;
2428 grub_uint32_t i = 0;
2429 grub_uint32_t sector = 0;
2430 grub_uint32_t count = 0;
2431 grub_off_t size = 0;
2432 grub_off_t read = 0;
2433
2434 fs_type = ventoy_get_fs_type(file->fs->name);
2435 if (fs_type == ventoy_fs_exfat)
2436 {
2437 grub_fat_get_file_chunk(start, file, chunklist);
2438 }
2439 else if (fs_type == ventoy_fs_ext)
2440 {
2441 grub_ext_get_file_chunk(start, file, chunklist);
2442 }
2443 else
2444 {
2445 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2446 file->read_hook_data = chunklist;
2447
2448 for (size = file->size; size > 0; size -= read)
2449 {
2450 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2451 grub_file_read(file, NULL, read);
2452 }
2453
2454 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2455 {
2456 chunklist->chunk[i].disk_start_sector += start;
2457 chunklist->chunk[i].disk_end_sector += start;
2458 }
2459
2460 if (ventoy_fs_udf == fs_type)
2461 {
2462 for (i = 0; i < chunklist->cur_chunk; i++)
2463 {
2464 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2465 chunklist->chunk[i].img_start_sector = sector;
2466 chunklist->chunk[i].img_end_sector = sector + count - 1;
2467 sector += count;
2468 }
2469 }
2470 }
2471
2472 len = (int)grub_strlen(file->name);
2473 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2474 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2475 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2476 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2477 {
2478 for (i = 0; i < chunklist->cur_chunk; i++)
2479 {
2480 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2481 if (count < 4)
2482 {
2483 count = 1;
2484 }
2485 else
2486 {
2487 count >>= 2;
2488 }
2489
2490 chunklist->chunk[i].img_start_sector = sector;
2491 chunklist->chunk[i].img_end_sector = sector + count - 1;
2492 sector += count;
2493 }
2494 }
2495
2496 return 0;
2497 }
2498
2499 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2500 {
2501 int rc;
2502 grub_file_t file;
2503 grub_disk_addr_t start;
2504
2505 (void)ctxt;
2506 (void)argc;
2507
2508 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2509 if (!file)
2510 {
2511 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2512 }
2513
2514 g_conf_replace_node = NULL;
2515 g_conf_replace_offset = 0;
2516
2517 if (g_img_chunk_list.chunk)
2518 {
2519 grub_free(g_img_chunk_list.chunk);
2520 }
2521
2522 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2523 {
2524 grub_file_close(file);
2525 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2526 }
2527
2528 /* get image chunk data */
2529 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2530 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2531 if (NULL == g_img_chunk_list.chunk)
2532 {
2533 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2534 }
2535
2536 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2537 g_img_chunk_list.cur_chunk = 0;
2538
2539 start = file->device->disk->partition->start;
2540
2541 ventoy_get_block_list(file, &g_img_chunk_list, start);
2542
2543 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2544 grub_file_close(file);
2545
2546 if (rc)
2547 {
2548 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2549 }
2550
2551 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2552 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2553 }
2554
2555 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2556 {
2557 grub_uint64_t offset = 0;
2558 grub_uint32_t align = 0;
2559 grub_file_t file = NULL;
2560 conf_replace *node = NULL;
2561
2562 (void)ctxt;
2563 (void)argc;
2564 (void)args;
2565
2566 debug("select conf replace argc:%d\n", argc);
2567
2568 if (argc < 2)
2569 {
2570 return 0;
2571 }
2572
2573 node = ventoy_plugin_find_conf_replace(args[1]);
2574 if (!node)
2575 {
2576 debug("Conf replace not found for %s\n", args[1]);
2577 goto end;
2578 }
2579
2580 debug("Find conf replace for %s\n", args[1]);
2581
2582 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2583 if (!file)
2584 {
2585 debug("<(loop)%s> NOT exist\n", node->orgconf);
2586 goto end;
2587 }
2588
2589 offset = grub_iso9660_get_last_file_dirent_pos(file);
2590 grub_file_close(file);
2591
2592 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2593 if (!file)
2594 {
2595 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2596 goto end;
2597 }
2598
2599 align = ((int)file->size + 2047) / 2048 * 2048;
2600
2601 if (align > vtoy_max_replace_file_size)
2602 {
2603 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2604 goto end;
2605 }
2606
2607 grub_file_read(file, g_conf_replace_new_buf, file->size);
2608 g_conf_replace_new_len = (int)file->size;
2609 g_conf_replace_new_len_align = align;
2610
2611 g_conf_replace_node = node;
2612 g_conf_replace_offset = offset + 2;
2613
2614 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2615
2616 end:
2617 if (file)
2618 {
2619 grub_file_close(file);
2620 }
2621 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2622 }
2623
2624 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2625 {
2626 int i = 0;
2627 int pos = 0;
2628 char *buf = NULL;
2629 char configfile[128];
2630 install_template *node = NULL;
2631
2632 (void)ctxt;
2633 (void)argc;
2634 (void)args;
2635
2636 debug("select auto installation argc:%d\n", argc);
2637
2638 if (argc < 1)
2639 {
2640 return 0;
2641 }
2642
2643 node = ventoy_plugin_find_install_template(args[0]);
2644 if (!node)
2645 {
2646 debug("Auto install template not found for %s\n", args[0]);
2647 return 0;
2648 }
2649
2650 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2651 {
2652 node->cursel = node->autosel - 1;
2653 debug("Auto install template auto select %d\n", node->autosel);
2654 return 0;
2655 }
2656
2657 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2658 if (!buf)
2659 {
2660 return 0;
2661 }
2662
2663 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2664 " echo %s\n}\n", "123");
2665
2666 for (i = 0; i < node->templatenum; i++)
2667 {
2668 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2669 " echo 123\n}\n",
2670 node->templatepath[i].path);
2671 }
2672
2673 g_ventoy_menu_esc = 1;
2674 g_ventoy_suppress_esc = 1;
2675
2676 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2677 grub_script_execute_sourcecode(configfile);
2678
2679 g_ventoy_menu_esc = 0;
2680 g_ventoy_suppress_esc = 0;
2681
2682 grub_free(buf);
2683
2684 node->cursel = g_ventoy_last_entry - 1;
2685
2686 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2687 }
2688
2689 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2690 {
2691 int i = 0;
2692 int pos = 0;
2693 char *buf = NULL;
2694 char configfile[128];
2695 persistence_config *node;
2696
2697 (void)ctxt;
2698 (void)argc;
2699 (void)args;
2700
2701 debug("select persistence argc:%d\n", argc);
2702
2703 if (argc < 1)
2704 {
2705 return 0;
2706 }
2707
2708 node = ventoy_plugin_find_persistent(args[0]);
2709 if (!node)
2710 {
2711 debug("Persistence image not found for %s\n", args[0]);
2712 return 0;
2713 }
2714
2715 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2716 {
2717 node->cursel = node->autosel - 1;
2718 debug("Persistence image auto select %d\n", node->autosel);
2719 return 0;
2720 }
2721
2722 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2723 if (!buf)
2724 {
2725 return 0;
2726 }
2727
2728 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2729 " echo %s\n}\n", "123");
2730
2731 for (i = 0; i < node->backendnum; i++)
2732 {
2733 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2734 " echo 123\n}\n",
2735 node->backendpath[i].path);
2736
2737 }
2738
2739 g_ventoy_menu_esc = 1;
2740 g_ventoy_suppress_esc = 1;
2741
2742 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2743 grub_script_execute_sourcecode(configfile);
2744
2745 g_ventoy_menu_esc = 0;
2746 g_ventoy_suppress_esc = 0;
2747
2748 grub_free(buf);
2749
2750 node->cursel = g_ventoy_last_entry - 1;
2751
2752 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2753 }
2754
2755 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2756 {
2757 grub_uint32_t i;
2758 ventoy_img_chunk *cur;
2759
2760 (void)ctxt;
2761 (void)argc;
2762 (void)args;
2763
2764 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2765 {
2766 cur = g_img_chunk_list.chunk + i;
2767 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2768 cur->img_start_sector, cur->img_end_sector,
2769 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2770 );
2771 }
2772
2773 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2774 }
2775
2776 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2777 {
2778 grub_uint32_t i;
2779 grub_file_t file;
2780 ventoy_img_chunk_list chunklist;
2781
2782 (void)ctxt;
2783 (void)argc;
2784
2785 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2786 if (!file)
2787 {
2788 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2789 }
2790
2791 /* get image chunk data */
2792 grub_memset(&chunklist, 0, sizeof(chunklist));
2793 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2794 if (NULL == chunklist.chunk)
2795 {
2796 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2797 }
2798
2799 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2800 chunklist.cur_chunk = 0;
2801
2802 ventoy_get_block_list(file, &chunklist, 0);
2803
2804 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2805 {
2806 grub_printf("########## UNSUPPORTED ###############\n");
2807 }
2808
2809 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2810
2811 for (i = 0; i < chunklist.cur_chunk; i++)
2812 {
2813 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2814 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2815 }
2816
2817 grub_printf("\n==================================\n");
2818
2819 for (i = 0; i < chunklist.cur_chunk; i++)
2820 {
2821 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2822 (ulonglong)chunklist.chunk[i].img_start_sector,
2823 (ulonglong)chunklist.chunk[i].img_end_sector,
2824 (ulonglong)chunklist.chunk[i].disk_start_sector,
2825 (ulonglong)chunklist.chunk[i].disk_end_sector
2826 );
2827 }
2828
2829 grub_free(chunklist.chunk);
2830 grub_file_close(file);
2831
2832 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2833 }
2834
2835 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2836 {
2837 int i;
2838 ventoy_grub_param_file_replace *replace = NULL;
2839
2840 (void)ctxt;
2841 (void)argc;
2842 (void)args;
2843
2844 if (argc >= 2)
2845 {
2846 replace = &(g_grub_param->file_replace);
2847 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2848
2849 replace->old_name_cnt = 0;
2850 for (i = 0; i < 4 && i + 1 < argc; i++)
2851 {
2852 replace->old_name_cnt++;
2853 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2854 }
2855
2856 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2857 }
2858
2859 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2860 }
2861
2862 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2863 {
2864 (void)ctxt;
2865 (void)argc;
2866 (void)args;
2867
2868 if (argc == 0)
2869 {
2870 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2871 grub_printf("%s", g_list_script_buf);
2872 }
2873 else
2874 {
2875 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2876 grub_printf("%s", g_tree_script_buf);
2877 }
2878
2879 return 0;
2880 }
2881
2882 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2883 {
2884 img_info *cur = g_ventoy_img_list;
2885
2886 (void)ctxt;
2887 (void)argc;
2888 (void)args;
2889
2890 while (cur)
2891 {
2892 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2893 grub_printf("name:<%s>\n\n", cur->name);
2894 cur = cur->next;
2895 }
2896
2897 return 0;
2898 }
2899
2900 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2901 {
2902 (void)ctxt;
2903 (void)argc;
2904 (void)args;
2905
2906 ventoy_plugin_dump_injection();
2907
2908 return 0;
2909 }
2910
2911 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2912 {
2913 (void)ctxt;
2914 (void)argc;
2915 (void)args;
2916
2917 ventoy_plugin_dump_auto_install();
2918
2919 return 0;
2920 }
2921
2922 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2923 {
2924 (void)ctxt;
2925 (void)argc;
2926 (void)args;
2927
2928 ventoy_plugin_dump_persistence();
2929
2930 return 0;
2931 }
2932
2933 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2934 {
2935 (void)ctxt;
2936 (void)argc;
2937 (void)args;
2938
2939 if (argc != 1)
2940 {
2941 return 1;
2942 }
2943
2944 if (args[0][0] == '0')
2945 {
2946 return g_ventoy_memdisk_mode ? 0 : 1;
2947 }
2948 else if (args[0][0] == '1')
2949 {
2950 return g_ventoy_iso_raw ? 0 : 1;
2951 }
2952 else if (args[0][0] == '2')
2953 {
2954 return g_ventoy_iso_uefi_drv ? 0 : 1;
2955 }
2956
2957 return 1;
2958 }
2959
2960 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2961 {
2962 static int configfile_mode = 0;
2963 char memfile[128] = {0};
2964
2965 (void)ctxt;
2966 (void)argc;
2967 (void)args;
2968
2969 /*
2970 * args[0]: 0:normal 1:configfile
2971 * args[1]: 0:list_buf 1:tree_buf
2972 */
2973
2974 if (argc != 2)
2975 {
2976 debug("Invalid argc %d\n", argc);
2977 return 0;
2978 }
2979
2980 if (args[0][0] == '0')
2981 {
2982 if (args[1][0] == '0')
2983 {
2984 grub_script_execute_sourcecode(g_list_script_buf);
2985 }
2986 else
2987 {
2988 grub_script_execute_sourcecode(g_tree_script_buf);
2989 }
2990 }
2991 else
2992 {
2993 if (configfile_mode)
2994 {
2995 debug("Now already in F3 mode %d\n", configfile_mode);
2996 return 0;
2997 }
2998
2999 if (args[1][0] == '0')
3000 {
3001 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3002 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3003 }
3004 else
3005 {
3006 g_ventoy_last_entry = -1;
3007 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3008 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3009 }
3010
3011 configfile_mode = 1;
3012 grub_script_execute_sourcecode(memfile);
3013 configfile_mode = 0;
3014 }
3015
3016 return 0;
3017 }
3018
3019 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3020 {
3021 grub_file_t file;
3022
3023 (void)ctxt;
3024
3025 if (argc != 1)
3026 {
3027 return 1;
3028 }
3029
3030 g_ventoy_case_insensitive = 1;
3031 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3032 g_ventoy_case_insensitive = 0;
3033
3034 grub_errno = 0;
3035
3036 if (file)
3037 {
3038 grub_file_close(file);
3039 return 0;
3040 }
3041 return 1;
3042 }
3043
3044 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3045 {
3046 int id = 0;
3047 int find = 0;
3048 grub_disk_t disk;
3049 const char *isopath = NULL;
3050 char hdname[32];
3051 ventoy_mbr_head mbr;
3052
3053 (void)ctxt;
3054 (void)argc;
3055
3056 if (argc != 1)
3057 {
3058 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3059 }
3060
3061 isopath = grub_env_get("vtoy_iso_part");
3062 if (!isopath)
3063 {
3064 debug("isopath is null %p\n", isopath);
3065 return 0;
3066 }
3067
3068 debug("isopath is %s\n", isopath);
3069
3070 for (id = 0; id < 30 && (find == 0); id++)
3071 {
3072 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3073 if (grub_strstr(isopath, hdname))
3074 {
3075 debug("skip %s ...\n", hdname);
3076 continue;
3077 }
3078
3079 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3080
3081 disk = grub_disk_open(hdname);
3082 if (!disk)
3083 {
3084 debug("%s not exist\n", hdname);
3085 break;
3086 }
3087
3088 grub_memset(&mbr, 0, sizeof(mbr));
3089 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3090 {
3091 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3092 {
3093 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3094 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3095 {
3096
3097 grub_env_set(args[0], hdname);
3098 find = 1;
3099 }
3100 }
3101 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3102 }
3103 else
3104 {
3105 debug("read %s failed\n", hdname);
3106 }
3107
3108 grub_disk_close(disk);
3109 }
3110
3111 return 0;
3112 }
3113
3114 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3115 {
3116 int len = 1024;
3117 grub_file_t file;
3118 char *buf = NULL;
3119
3120 (void)ctxt;
3121 (void)argc;
3122
3123 if (argc != 2)
3124 {
3125 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3126 }
3127
3128 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3129 if (!file)
3130 {
3131 debug("failed to open file %s\n", args[0]);
3132 return 0;
3133 }
3134
3135 buf = grub_malloc(len);
3136 if (!buf)
3137 {
3138 goto end;
3139 }
3140
3141 buf[len - 1] = 0;
3142 grub_file_read(file, buf, len - 1);
3143
3144 ventoy_get_line(buf);
3145 ventoy_set_env(args[1], buf);
3146
3147 end:
3148
3149 grub_check_free(buf);
3150 grub_file_close(file);
3151
3152 return 0;
3153 }
3154
3155 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3156 {
3157 (void)disk;
3158 (void)data;
3159
3160 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3161 "0 %llu linear /dev/ventoy %llu\n",
3162 (ulonglong)partition->len, (ulonglong)partition->start);
3163
3164 return 0;
3165 }
3166
3167 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3168 {
3169 char *device_name = NULL;
3170 grub_device_t dev = NULL;
3171 char buf[64];
3172
3173 (void)ctxt;
3174
3175 g_part_list_pos = 0;
3176 grub_env_unset("vtoy_img_part_file");
3177
3178 if (argc != 1)
3179 {
3180 return 1;
3181 }
3182
3183 device_name = grub_file_get_device_name(args[0]);
3184 if (!device_name)
3185 {
3186 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3187 goto end;
3188 }
3189
3190 dev = grub_device_open(device_name);
3191 if (!dev)
3192 {
3193 debug("grub_device_open failed, %s\n", device_name);
3194 goto end;
3195 }
3196
3197 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3198
3199 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3200 grub_env_set("vtoy_img_part_file", buf);
3201
3202 end:
3203
3204 check_free(device_name, grub_free);
3205 check_free(dev, grub_device_close);
3206
3207 return 0;
3208 }
3209
3210
3211 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3212 {
3213 int rc = 1;
3214 grub_file_t file;
3215 char *buf = NULL;
3216
3217 (void)ctxt;
3218 (void)argc;
3219
3220 if (argc != 2)
3221 {
3222 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3223 }
3224
3225 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3226 if (!file)
3227 {
3228 debug("failed to open file %s\n", args[0]);
3229 return 1;
3230 }
3231
3232 buf = grub_malloc(file->size + 1);
3233 if (!buf)
3234 {
3235 goto end;
3236 }
3237
3238 buf[file->size] = 0;
3239 grub_file_read(file, buf, file->size);
3240
3241 if (grub_strstr(buf, args[1]))
3242 {
3243 rc = 0;
3244 }
3245
3246 end:
3247
3248 grub_check_free(buf);
3249 grub_file_close(file);
3250
3251 return rc;
3252 }
3253
3254 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3255 {
3256 int len;
3257 grub_file_t file;
3258 char buf[64];
3259 grub_uint64_t size;
3260 ventoy_iso9660_vd pvd;
3261
3262 (void)ctxt;
3263 (void)argc;
3264
3265 if (argc != 4)
3266 {
3267 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3268 }
3269
3270 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3271 if (!file)
3272 {
3273 debug("failed to open file %s\n", args[0]);
3274 return 0;
3275 }
3276
3277 grub_file_seek(file, 16 * 2048);
3278 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3279 if (len != sizeof(pvd))
3280 {
3281 debug("failed to read pvd %d\n", len);
3282 goto end;
3283 }
3284
3285 grub_memset(buf, 0, sizeof(buf));
3286 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3287 ventoy_set_env(args[1], buf);
3288
3289 grub_memset(buf, 0, sizeof(buf));
3290 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3291 ventoy_set_env(args[2], buf);
3292
3293 size = pvd.space;
3294 size *= 2048;
3295 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3296 ventoy_set_env(args[3], buf);
3297
3298 end:
3299 grub_file_close(file);
3300
3301 return 0;
3302 }
3303
3304 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3305 {
3306 int len;
3307 grub_file_t file;
3308 char buf[64];
3309
3310 (void)ctxt;
3311 (void)argc;
3312
3313 if (argc != 2)
3314 {
3315 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3316 }
3317
3318 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3319 if (!file)
3320 {
3321 debug("failed to open file %s\n", args[0]);
3322 return 0;
3323 }
3324
3325 grub_memset(buf, 0, sizeof(buf));
3326 grub_file_seek(file, 16 * 2048 + 813);
3327 len = (int)grub_file_read(file, buf, 17);
3328 if (len != 17)
3329 {
3330 debug("failed to read create date %d\n", len);
3331 goto end;
3332 }
3333
3334 ventoy_set_env(args[1], buf);
3335
3336 end:
3337 grub_file_close(file);
3338
3339 return 0;
3340 }
3341
3342 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3343 {
3344 (void)ctxt;
3345 (void)argc;
3346 (void)args;
3347
3348 ventoy_env_hook_root(1);
3349
3350 return 0;
3351 }
3352
3353 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3354 {
3355 (void)ctxt;
3356 (void)argc;
3357 (void)args;
3358
3359 ventoy_env_hook_root(0);
3360
3361 return 0;
3362 }
3363
3364 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3365 {
3366 int i;
3367 int buflen;
3368 int datalen;
3369 int loclen;
3370 int img_chunk_num;
3371 int image_sector_size;
3372 char cmd[64];
3373 ventoy_chain_head *chain;
3374 ventoy_img_chunk *chunk;
3375 ventoy_os_param *osparam;
3376 ventoy_image_location *location;
3377 ventoy_image_disk_region *region;
3378 struct grub_acpi_table_header *acpi;
3379
3380 (void)ctxt;
3381
3382 if (argc != 2)
3383 {
3384 return 1;
3385 }
3386
3387 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3388
3389 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3390 if (!chain)
3391 {
3392 return 1;
3393 }
3394
3395 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3396
3397 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3398 {
3399 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3400 return 1;
3401 }
3402
3403 img_chunk_num = chain->img_chunk_num;
3404
3405 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3406 datalen = sizeof(ventoy_os_param) + loclen;
3407
3408 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3409 acpi = grub_zalloc(buflen);
3410 if (!acpi)
3411 {
3412 return 1;
3413 }
3414
3415 /* Step1: Fill acpi table header */
3416 grub_memcpy(acpi->signature, "VTOY", 4);
3417 acpi->length = buflen;
3418 acpi->revision = 1;
3419 grub_memcpy(acpi->oemid, "VENTOY", 6);
3420 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3421 acpi->oemrev = 1;
3422 acpi->creator_id[0] = 1;
3423 acpi->creator_rev = 1;
3424
3425 /* Step2: Fill data */
3426 osparam = (ventoy_os_param *)(acpi + 1);
3427 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3428 osparam->vtoy_img_location_addr = 0;
3429 osparam->vtoy_img_location_len = loclen;
3430 osparam->chksum = 0;
3431 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3432
3433 location = (ventoy_image_location *)(osparam + 1);
3434 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3435 location->image_sector_size = image_sector_size;
3436 location->disk_sector_size = chain->disk_sector_size;
3437 location->region_count = img_chunk_num;
3438
3439 region = location->regions;
3440 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3441 if (512 == image_sector_size)
3442 {
3443 for (i = 0; i < img_chunk_num; i++)
3444 {
3445 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3446 region->image_start_sector = chunk->img_start_sector * 4;
3447 region->disk_start_sector = chunk->disk_start_sector;
3448 region++;
3449 chunk++;
3450 }
3451 }
3452 else
3453 {
3454 for (i = 0; i < img_chunk_num; i++)
3455 {
3456 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3457 region->image_start_sector = chunk->img_start_sector;
3458 region->disk_start_sector = chunk->disk_start_sector;
3459 region++;
3460 chunk++;
3461 }
3462 }
3463
3464 /* Step3: Fill acpi checksum */
3465 acpi->checksum = 0;
3466 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3467
3468 /* load acpi table */
3469 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3470 grub_script_execute_sourcecode(cmd);
3471
3472 grub_free(acpi);
3473
3474 VENTOY_CMD_RETURN(0);
3475 }
3476
3477 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3478 {
3479 (void)ctxt;
3480 (void)argc;
3481 (void)args;
3482
3483 g_ventoy_last_entry_back = g_ventoy_last_entry;
3484 g_ventoy_last_entry = -1;
3485
3486 return 0;
3487 }
3488
3489 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3490 {
3491 (void)ctxt;
3492 (void)argc;
3493 (void)args;
3494
3495 g_ventoy_last_entry = g_ventoy_last_entry_back;
3496
3497 return 0;
3498 }
3499
3500 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3501 {
3502 grub_uint64_t sectors;
3503
3504 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3505 {
3506 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3507 }
3508 else
3509 {
3510 sectors = gpt->MBR.PartTbl[0].SectorCount;
3511 }
3512
3513 return sectors * 512;
3514 }
3515
3516 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3517 {
3518 const char *pos = filename + 1;
3519
3520 if (info->dir)
3521 {
3522 while (*pos)
3523 {
3524 if (*pos == '.')
3525 {
3526 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3527 {
3528 grub_strncpy((char *)data, filename, 128);
3529 return 1;
3530 }
3531 }
3532 pos++;
3533 }
3534 }
3535
3536 return 0;
3537 }
3538
3539 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3540 {
3541 int rc = 1;
3542 char *device_name = NULL;
3543 grub_device_t dev = NULL;
3544 grub_fs_t fs = NULL;
3545 char buf[128] = {0};
3546
3547 (void)ctxt;
3548
3549 if (argc != 3)
3550 {
3551 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3552 return 1;
3553 }
3554
3555 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3556
3557 device_name = grub_file_get_device_name(args[0]);
3558 if (!device_name)
3559 {
3560 debug("grub_file_get_device_name failed, %s\n", args[0]);
3561 goto end;
3562 }
3563
3564 dev = grub_device_open(device_name);
3565 if (!dev)
3566 {
3567 debug("grub_device_open failed, %s\n", device_name);
3568 goto end;
3569 }
3570
3571 fs = grub_fs_probe(dev);
3572 if (!fs)
3573 {
3574 debug("grub_fs_probe failed, %s\n", device_name);
3575 goto end;
3576 }
3577
3578 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3579
3580 if (buf[0])
3581 {
3582 ventoy_set_env(args[2], buf);
3583 }
3584
3585 rc = 0;
3586
3587 end:
3588
3589 check_free(device_name, grub_free);
3590 check_free(dev, grub_device_close);
3591
3592 return rc;
3593 }
3594
3595 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3596 {
3597 char name[64];
3598 int ret;
3599 grub_disk_t disk;
3600 grub_device_t dev;
3601
3602 (void)argc;
3603 (void)ctxt;
3604
3605 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3606 if (!g_ventoy_part_info)
3607 {
3608 return 1;
3609 }
3610
3611 disk = grub_disk_open(args[0]);
3612 if (!disk)
3613 {
3614 debug("Failed to open disk %s\n", args[0]);
3615 return 1;
3616 }
3617
3618 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3619
3620 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3621 grub_disk_close(disk);
3622
3623 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3624 dev = grub_device_open(name);
3625 if (dev)
3626 {
3627 /* make sure that we are running in a correct Ventoy device */
3628 ret = ventoy_check_device(dev);
3629 grub_device_close(dev);
3630
3631 if (ret)
3632 {
3633 grub_exit();
3634 }
3635 }
3636
3637 return 0;
3638 }
3639
3640 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3641 {
3642 int id;
3643 grub_uint8_t zeroguid[16] = {0};
3644
3645 (void)argc;
3646 (void)ctxt;
3647
3648 id = (int)grub_strtoul(args[0], NULL, 10);
3649 grub_errno = 0;
3650
3651 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3652 {
3653 if (id >= 1 && id <= 128)
3654 {
3655 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3656 {
3657 return 0;
3658 }
3659 }
3660 }
3661 else
3662 {
3663 if (id >= 1 && id <= 4)
3664 {
3665 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3666 {
3667 return 0;
3668 }
3669 }
3670 }
3671
3672 return 1;
3673 }
3674
3675 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3676 {
3677 int rc = 1;
3678 char *device_name = NULL;
3679 grub_device_t dev = NULL;
3680 grub_fs_t fs = NULL;
3681 char *label = NULL;
3682
3683 (void)ctxt;
3684
3685 if (argc != 2)
3686 {
3687 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3688 return 1;
3689 }
3690
3691 device_name = grub_file_get_device_name(args[0]);
3692 if (!device_name)
3693 {
3694 debug("grub_file_get_device_name failed, %s\n", args[0]);
3695 goto end;
3696 }
3697
3698 dev = grub_device_open(device_name);
3699 if (!dev)
3700 {
3701 debug("grub_device_open failed, %s\n", device_name);
3702 goto end;
3703 }
3704
3705 fs = grub_fs_probe(dev);
3706 if (!fs)
3707 {
3708 debug("grub_fs_probe failed, %s\n", device_name);
3709 goto end;
3710 }
3711
3712 fs->fs_label(dev, &label);
3713 if (label)
3714 {
3715 ventoy_set_env(args[1], label);
3716 grub_free(label);
3717 }
3718
3719 rc = 0;
3720
3721 end:
3722
3723 check_free(device_name, grub_free);
3724 check_free(dev, grub_device_close);
3725
3726 return rc;
3727 }
3728
3729 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3730 {
3731 if (!info->dir)
3732 {
3733 grub_snprintf((char *)data, 256, "%s", filename);
3734 return 1;
3735 }
3736
3737 return 0;
3738 }
3739
3740
3741 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3742 {
3743 int rc = 1;
3744 char *device_name = NULL;
3745 grub_device_t dev = NULL;
3746 grub_fs_t fs = NULL;
3747 char name[256] ={0};
3748
3749 (void)ctxt;
3750
3751 if (argc != 3)
3752 {
3753 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3754 return 1;
3755 }
3756
3757 device_name = grub_file_get_device_name(args[0]);
3758 if (!device_name)
3759 {
3760 debug("grub_file_get_device_name failed, %s\n", args[0]);
3761 goto end;
3762 }
3763
3764 dev = grub_device_open(device_name);
3765 if (!dev)
3766 {
3767 debug("grub_device_open failed, %s\n", device_name);
3768 goto end;
3769 }
3770
3771 fs = grub_fs_probe(dev);
3772 if (!fs)
3773 {
3774 debug("grub_fs_probe failed, %s\n", device_name);
3775 goto end;
3776 }
3777
3778 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3779 if (name[0])
3780 {
3781 ventoy_set_env(args[2], name);
3782 }
3783
3784 rc = 0;
3785
3786 end:
3787
3788 check_free(device_name, grub_free);
3789 check_free(dev, grub_device_close);
3790
3791 return rc;
3792 }
3793
3794 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3795 {
3796 char c;
3797 char *pos = NULL;
3798 char *end = NULL;
3799
3800 (void)ctxt;
3801
3802 if (argc != 2)
3803 {
3804 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3805 return 1;
3806 }
3807
3808 for (pos = args[0]; *pos; pos++)
3809 {
3810 if (*pos == '.')
3811 {
3812 end = pos;
3813 }
3814 }
3815
3816 if (end)
3817 {
3818 c = *end;
3819 *end = 0;
3820 }
3821
3822 grub_env_set(args[1], args[0]);
3823
3824 if (end)
3825 {
3826 *end = c;
3827 }
3828
3829 return 0;
3830 }
3831
3832 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3833 {
3834 struct grub_video_mode_info info;
3835 char buf[32];
3836
3837 (void)ctxt;
3838 (void)argc;
3839 (void)args;
3840
3841 if (!g_video_mode_list)
3842 {
3843 ventoy_enum_video_mode();
3844 }
3845
3846 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3847 {
3848 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3849 }
3850 else
3851 {
3852 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3853 }
3854
3855 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3856
3857 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3858 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3859
3860 VENTOY_CMD_RETURN(0);
3861 }
3862
3863 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3864 {
3865 struct grub_video_mode_info info;
3866 char buf[32];
3867
3868 (void)ctxt;
3869 (void)argc;
3870 (void)args;
3871
3872 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3873 {
3874 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
3875 }
3876 else
3877 {
3878 grub_snprintf(buf, sizeof(buf), "0x0x0");
3879 }
3880
3881 grub_env_set(args[0], buf);
3882
3883 VENTOY_CMD_RETURN(0);
3884 }
3885
3886 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3887 {
3888 int id;
3889 char buf[32];
3890
3891 (void)ctxt;
3892 (void)argc;
3893
3894 if (!g_video_mode_list)
3895 {
3896 return 0;
3897 }
3898
3899 id = (int)grub_strtoul(args[0], NULL, 10);
3900 if (id < g_video_mode_num)
3901 {
3902 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
3903 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
3904 }
3905
3906 grub_env_set(args[1], buf);
3907
3908 VENTOY_CMD_RETURN(0);
3909 }
3910
3911 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
3912 {
3913 grub_uint64_t size = 0;
3914 grub_file_t file;
3915 va_list ap;
3916 char fullpath[256] = {0};
3917
3918 va_start (ap, fmt);
3919 grub_vsnprintf(fullpath, 255, fmt, ap);
3920 va_end (ap);
3921
3922 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
3923 if (!file)
3924 {
3925 debug("grub_file_open failed <%s>\n", fullpath);
3926 grub_errno = 0;
3927 return 0;
3928 }
3929
3930 size = file->size;
3931 grub_file_close(file);
3932 return size;
3933 }
3934
3935 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
3936 {
3937 va_list ap;
3938 grub_file_t file;
3939 char fullpath[256] = {0};
3940
3941 va_start (ap, fmt);
3942 grub_vsnprintf(fullpath, 255, fmt, ap);
3943 va_end (ap);
3944
3945 file = grub_file_open(fullpath, type);
3946 if (!file)
3947 {
3948 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
3949 grub_errno = 0;
3950 }
3951
3952 return file;
3953 }
3954
3955 int ventoy_is_file_exist(const char *fmt, ...)
3956 {
3957 va_list ap;
3958 int len;
3959 char *pos = NULL;
3960 char buf[256] = {0};
3961
3962 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
3963 pos = buf + 6;
3964
3965 va_start (ap, fmt);
3966 len = grub_vsnprintf(pos, 255, fmt, ap);
3967 va_end (ap);
3968
3969 grub_strncpy(pos + len, "\" ]", 3);
3970
3971 debug("script exec %s\n", buf);
3972
3973 if (0 == grub_script_execute_sourcecode(buf))
3974 {
3975 return 1;
3976 }
3977
3978 return 0;
3979 }
3980
3981 int ventoy_is_dir_exist(const char *fmt, ...)
3982 {
3983 va_list ap;
3984 int len;
3985 char *pos = NULL;
3986 char buf[256] = {0};
3987
3988 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
3989 pos = buf + 6;
3990
3991 va_start (ap, fmt);
3992 len = grub_vsnprintf(pos, 255, fmt, ap);
3993 va_end (ap);
3994
3995 grub_strncpy(pos + len, "\" ]", 3);
3996
3997 debug("script exec %s\n", buf);
3998
3999 if (0 == grub_script_execute_sourcecode(buf))
4000 {
4001 return 1;
4002 }
4003
4004 return 0;
4005 }
4006
4007 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
4008 {
4009 mz_stream s;
4010 grub_uint8_t *outbuf;
4011 grub_uint8_t gzHdr[10] =
4012 {
4013 0x1F, 0x8B, /* magic */
4014 8, /* z method */
4015 0, /* flags */
4016 0,0,0,0, /* mtime */
4017 4, /* xfl */
4018 3, /* OS */
4019 };
4020
4021 grub_memset(&s, 0, sizeof(mz_stream));
4022
4023 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
4024
4025 outbuf = (grub_uint8_t *)mem_out;
4026
4027 mem_out_len -= sizeof(gzHdr) + 8;
4028 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
4029 outbuf += sizeof(gzHdr);
4030
4031 s.avail_in = mem_in_len;
4032 s.next_in = mem_in;
4033
4034 s.avail_out = mem_out_len;
4035 s.next_out = outbuf;
4036
4037 mz_deflate(&s, MZ_FINISH);
4038
4039 mz_deflateEnd(&s);
4040
4041 outbuf += s.total_out;
4042 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4043 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4044
4045 return s.total_out + sizeof(gzHdr) + 8;
4046 }
4047
4048 static int ventoy_env_init(void)
4049 {
4050 char buf[64];
4051
4052 grub_env_set("vtdebug_flag", "");
4053
4054 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4055 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4056 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4057 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4058
4059 ventoy_filt_register(0, ventoy_wrapper_open);
4060
4061 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4062 if (g_grub_param)
4063 {
4064 g_grub_param->grub_env_get = grub_env_get;
4065 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4066 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4067 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4068 grub_env_set("env_param", buf);
4069 grub_env_set("ventoy_env_param", buf);
4070 grub_env_export("ventoy_env_param");
4071 }
4072
4073 return 0;
4074 }
4075
4076 static cmd_para ventoy_cmds[] =
4077 {
4078 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4079 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4080 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4081 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4082 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4083 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4084 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4085 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4086 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4087 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4088 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4089 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4090 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4091 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4092 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4093 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4094 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4095 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4096 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4097 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4098 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4099
4100 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4101 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4102 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4103 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4104 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4105 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4106 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4107
4108 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4109 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4110 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4111 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4112 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4113 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4114 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4115 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4116
4117
4118 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4119 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4120 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4121 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4122 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4123 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4124 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4125 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4126 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4127 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4128 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4129
4130 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4131 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4132 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4133 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4134 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4135 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4136
4137 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4138 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4139 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4140 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4141 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4142 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4143 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4144 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4145 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4146 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4147
4148 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4149 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4150 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4151 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4152 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4153 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4154 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4155 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4156
4157 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4158 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4159 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4160
4161
4162 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4163 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4164 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4165
4166 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4167 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4168 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4169
4170
4171 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4172 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4173 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4174 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4175 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4176 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4177 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4178 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4179 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4180 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4181
4182 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4183 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4184 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4185
4186 };
4187
4188
4189
4190 GRUB_MOD_INIT(ventoy)
4191 {
4192 grub_uint32_t i;
4193 cmd_para *cur = NULL;
4194
4195 ventoy_env_init();
4196
4197 ventoy_arch_mode_init();
4198
4199 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4200 {
4201 cur = ventoy_cmds + i;
4202 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4203 cur->summary, cur->description, cur->parser);
4204 }
4205 }
4206
4207 GRUB_MOD_FINI(ventoy)
4208 {
4209 grub_uint32_t i;
4210
4211 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4212 {
4213 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4214 }
4215 }
4216