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