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