]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
848ba8746a2bceadab33883f4201ce4f8b5afd33
[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 (void)disk;
3495 (void)data;
3496
3497 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3498 "0 %llu linear /dev/ventoy %llu\n",
3499 (ulonglong)partition->len, (ulonglong)partition->start);
3500
3501 return 0;
3502 }
3503
3504 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3505 {
3506 char *device_name = NULL;
3507 grub_device_t dev = NULL;
3508 char buf[64];
3509
3510 (void)ctxt;
3511
3512 g_part_list_pos = 0;
3513 grub_env_unset("vtoy_img_part_file");
3514
3515 if (argc != 1)
3516 {
3517 return 1;
3518 }
3519
3520 device_name = grub_file_get_device_name(args[0]);
3521 if (!device_name)
3522 {
3523 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3524 goto end;
3525 }
3526
3527 dev = grub_device_open(device_name);
3528 if (!dev)
3529 {
3530 debug("grub_device_open failed, %s\n", device_name);
3531 goto end;
3532 }
3533
3534 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3535
3536 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3537 grub_env_set("vtoy_img_part_file", buf);
3538
3539 end:
3540
3541 check_free(device_name, grub_free);
3542 check_free(dev, grub_device_close);
3543
3544 return 0;
3545 }
3546
3547
3548 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3549 {
3550 int rc = 1;
3551 grub_file_t file;
3552 char *buf = NULL;
3553
3554 (void)ctxt;
3555 (void)argc;
3556
3557 if (argc != 2)
3558 {
3559 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3560 }
3561
3562 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3563 if (!file)
3564 {
3565 debug("failed to open file %s\n", args[0]);
3566 return 1;
3567 }
3568
3569 buf = grub_malloc(file->size + 1);
3570 if (!buf)
3571 {
3572 goto end;
3573 }
3574
3575 buf[file->size] = 0;
3576 grub_file_read(file, buf, file->size);
3577
3578 if (grub_strstr(buf, args[1]))
3579 {
3580 rc = 0;
3581 }
3582
3583 end:
3584
3585 grub_check_free(buf);
3586 grub_file_close(file);
3587
3588 return rc;
3589 }
3590
3591 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3592 {
3593 int len;
3594 grub_file_t file;
3595 char buf[64];
3596 grub_uint64_t size;
3597 ventoy_iso9660_vd pvd;
3598
3599 (void)ctxt;
3600 (void)argc;
3601
3602 if (argc != 4)
3603 {
3604 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3605 }
3606
3607 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3608 if (!file)
3609 {
3610 debug("failed to open file %s\n", args[0]);
3611 return 0;
3612 }
3613
3614 grub_file_seek(file, 16 * 2048);
3615 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3616 if (len != sizeof(pvd))
3617 {
3618 debug("failed to read pvd %d\n", len);
3619 goto end;
3620 }
3621
3622 grub_memset(buf, 0, sizeof(buf));
3623 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3624 ventoy_set_env(args[1], buf);
3625
3626 grub_memset(buf, 0, sizeof(buf));
3627 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3628 ventoy_set_env(args[2], buf);
3629
3630 size = pvd.space;
3631 size *= 2048;
3632 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3633 ventoy_set_env(args[3], buf);
3634
3635 end:
3636 grub_file_close(file);
3637
3638 return 0;
3639 }
3640
3641 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3642 {
3643 int len;
3644 grub_file_t file;
3645 char buf[64];
3646
3647 (void)ctxt;
3648 (void)argc;
3649
3650 if (argc != 2)
3651 {
3652 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3653 }
3654
3655 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3656 if (!file)
3657 {
3658 debug("failed to open file %s\n", args[0]);
3659 return 0;
3660 }
3661
3662 grub_memset(buf, 0, sizeof(buf));
3663 grub_file_seek(file, 16 * 2048 + 813);
3664 len = (int)grub_file_read(file, buf, 17);
3665 if (len != 17)
3666 {
3667 debug("failed to read create date %d\n", len);
3668 goto end;
3669 }
3670
3671 ventoy_set_env(args[1], buf);
3672
3673 end:
3674 grub_file_close(file);
3675
3676 return 0;
3677 }
3678
3679 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3680 {
3681 (void)ctxt;
3682 (void)argc;
3683 (void)args;
3684
3685 ventoy_env_hook_root(1);
3686
3687 return 0;
3688 }
3689
3690 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3691 {
3692 (void)ctxt;
3693 (void)argc;
3694 (void)args;
3695
3696 ventoy_env_hook_root(0);
3697
3698 return 0;
3699 }
3700
3701 #ifdef GRUB_MACHINE_EFI
3702 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3703 {
3704 int ret = 1;
3705 grub_uint8_t *var;
3706 grub_size_t size;
3707 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3708
3709 (void)ctxt;
3710 (void)argc;
3711 (void)args;
3712
3713 var = grub_efi_get_variable("SecureBoot", &global, &size);
3714 if (var && *var == 1)
3715 {
3716 return 0;
3717 }
3718
3719 return ret;
3720 }
3721 #else
3722 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3723 {
3724 (void)ctxt;
3725 (void)argc;
3726 (void)args;
3727 return 1;
3728 }
3729 #endif
3730
3731 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3732 {
3733 int i;
3734 int ret = 1;
3735 grub_file_t file;
3736 grub_uint64_t FileSectors = 0;
3737 ventoy_gpt_info *gpt = NULL;
3738 ventoy_part_table *pt = NULL;
3739 grub_uint8_t zeroguid[16] = {0};
3740
3741 (void)ctxt;
3742 (void)argc;
3743
3744 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3745 if (!file)
3746 {
3747 debug("failed to open file %s\n", args[0]);
3748 return 1;
3749 }
3750
3751 if (file->size % 512)
3752 {
3753 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3754 goto out;
3755 }
3756
3757 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3758 if (!gpt)
3759 {
3760 goto out;
3761 }
3762
3763 FileSectors = file->size / 512;
3764
3765 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3766 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3767 {
3768 debug("This is EFI partition table\n");
3769
3770 for (i = 0; i < 128; i++)
3771 {
3772 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3773 {
3774 if (FileSectors < gpt->PartTbl[i].LastLBA)
3775 {
3776 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3777 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3778 goto out;
3779 }
3780 }
3781 }
3782 }
3783 else
3784 {
3785 debug("This is MBR partition table\n");
3786
3787 for (i = 0; i < 4; i++)
3788 {
3789 pt = gpt->MBR.PartTbl + i;
3790 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3791 {
3792 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3793 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3794 (ulonglong)FileSectors);
3795 goto out;
3796 }
3797 }
3798 }
3799
3800 ret = 0;
3801
3802 out:
3803 grub_file_close(file);
3804 grub_check_free(gpt);
3805 grub_errno = GRUB_ERR_NONE;
3806 return ret;
3807 }
3808
3809 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3810 {
3811 int i;
3812 int ret;
3813
3814 (void)ctxt;
3815 (void)argc;
3816 (void)args;
3817
3818 for (i = 0; i < 500; i++)
3819 {
3820 ret = grub_getkey_noblock();
3821 if (ret == GRUB_TERM_NO_KEY)
3822 {
3823 break;
3824 }
3825 }
3826
3827 if (i >= 500)
3828 {
3829 grub_cls();
3830 grub_printf("\n\n Still have key input after clear.\n");
3831 grub_refresh();
3832 grub_sleep(5);
3833 }
3834
3835 return 0;
3836 }
3837
3838 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3839 {
3840 int i;
3841 int buflen;
3842 int datalen;
3843 int loclen;
3844 int img_chunk_num;
3845 int image_sector_size;
3846 char cmd[64];
3847 ventoy_chain_head *chain;
3848 ventoy_img_chunk *chunk;
3849 ventoy_os_param *osparam;
3850 ventoy_image_location *location;
3851 ventoy_image_disk_region *region;
3852 struct grub_acpi_table_header *acpi;
3853
3854 (void)ctxt;
3855
3856 if (argc != 2)
3857 {
3858 return 1;
3859 }
3860
3861 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3862
3863 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3864 if (!chain)
3865 {
3866 return 1;
3867 }
3868
3869 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3870
3871 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3872 {
3873 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3874 return 1;
3875 }
3876
3877 img_chunk_num = chain->img_chunk_num;
3878
3879 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3880 datalen = sizeof(ventoy_os_param) + loclen;
3881
3882 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3883 acpi = grub_zalloc(buflen);
3884 if (!acpi)
3885 {
3886 return 1;
3887 }
3888
3889 /* Step1: Fill acpi table header */
3890 grub_memcpy(acpi->signature, "VTOY", 4);
3891 acpi->length = buflen;
3892 acpi->revision = 1;
3893 grub_memcpy(acpi->oemid, "VENTOY", 6);
3894 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3895 acpi->oemrev = 1;
3896 acpi->creator_id[0] = 1;
3897 acpi->creator_rev = 1;
3898
3899 /* Step2: Fill data */
3900 osparam = (ventoy_os_param *)(acpi + 1);
3901 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3902 osparam->vtoy_img_location_addr = 0;
3903 osparam->vtoy_img_location_len = loclen;
3904 osparam->chksum = 0;
3905 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3906
3907 location = (ventoy_image_location *)(osparam + 1);
3908 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3909 location->image_sector_size = image_sector_size;
3910 location->disk_sector_size = chain->disk_sector_size;
3911 location->region_count = img_chunk_num;
3912
3913 region = location->regions;
3914 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3915 if (512 == image_sector_size)
3916 {
3917 for (i = 0; i < img_chunk_num; i++)
3918 {
3919 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3920 region->image_start_sector = chunk->img_start_sector * 4;
3921 region->disk_start_sector = chunk->disk_start_sector;
3922 region++;
3923 chunk++;
3924 }
3925 }
3926 else
3927 {
3928 for (i = 0; i < img_chunk_num; i++)
3929 {
3930 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3931 region->image_start_sector = chunk->img_start_sector;
3932 region->disk_start_sector = chunk->disk_start_sector;
3933 region++;
3934 chunk++;
3935 }
3936 }
3937
3938 /* Step3: Fill acpi checksum */
3939 acpi->checksum = 0;
3940 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3941
3942 /* load acpi table */
3943 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3944 grub_script_execute_sourcecode(cmd);
3945
3946 grub_free(acpi);
3947
3948 VENTOY_CMD_RETURN(0);
3949 }
3950
3951 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3952 {
3953 (void)ctxt;
3954 (void)argc;
3955 (void)args;
3956
3957 g_ventoy_last_entry_back = g_ventoy_last_entry;
3958 g_ventoy_last_entry = -1;
3959
3960 return 0;
3961 }
3962
3963 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3964 {
3965 (void)ctxt;
3966 (void)argc;
3967 (void)args;
3968
3969 g_ventoy_last_entry = g_ventoy_last_entry_back;
3970
3971 return 0;
3972 }
3973
3974 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3975 {
3976 const char *pos = filename + 1;
3977
3978 if (info->dir)
3979 {
3980 while (*pos)
3981 {
3982 if (*pos == '.')
3983 {
3984 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3985 {
3986 grub_strncpy((char *)data, filename, 128);
3987 return 1;
3988 }
3989 }
3990 pos++;
3991 }
3992 }
3993
3994 return 0;
3995 }
3996
3997 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3998 {
3999 int rc = 1;
4000 char *device_name = NULL;
4001 grub_device_t dev = NULL;
4002 grub_fs_t fs = NULL;
4003 char buf[128] = {0};
4004
4005 (void)ctxt;
4006
4007 if (argc != 3)
4008 {
4009 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4010 return 1;
4011 }
4012
4013 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4014
4015 device_name = grub_file_get_device_name(args[0]);
4016 if (!device_name)
4017 {
4018 debug("grub_file_get_device_name failed, %s\n", args[0]);
4019 goto end;
4020 }
4021
4022 dev = grub_device_open(device_name);
4023 if (!dev)
4024 {
4025 debug("grub_device_open failed, %s\n", device_name);
4026 goto end;
4027 }
4028
4029 fs = grub_fs_probe(dev);
4030 if (!fs)
4031 {
4032 debug("grub_fs_probe failed, %s\n", device_name);
4033 goto end;
4034 }
4035
4036 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4037
4038 if (buf[0])
4039 {
4040 ventoy_set_env(args[2], buf);
4041 }
4042
4043 rc = 0;
4044
4045 end:
4046
4047 check_free(device_name, grub_free);
4048 check_free(dev, grub_device_close);
4049
4050 return rc;
4051 }
4052
4053 int ventoy_load_part_table(const char *diskname)
4054 {
4055 char name[64];
4056 int ret;
4057 grub_disk_t disk;
4058 grub_device_t dev;
4059
4060 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4061 if (!g_ventoy_part_info)
4062 {
4063 return 1;
4064 }
4065
4066 disk = grub_disk_open(diskname);
4067 if (!disk)
4068 {
4069 debug("Failed to open disk %s\n", diskname);
4070 return 1;
4071 }
4072
4073 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4074
4075 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4076 grub_disk_close(disk);
4077
4078 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4079 dev = grub_device_open(name);
4080 if (dev)
4081 {
4082 /* Check for official Ventoy device */
4083 ret = ventoy_check_official_device(dev);
4084 grub_device_close(dev);
4085
4086 if (ret)
4087 {
4088 return 1;
4089 }
4090 }
4091
4092 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4093 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4094
4095 return 0;
4096 }
4097
4098 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4099 {
4100 int ret;
4101
4102 (void)argc;
4103 (void)ctxt;
4104
4105 ret = ventoy_load_part_table(args[0]);
4106 if (ret)
4107 {
4108 grub_exit();
4109 }
4110
4111 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4112 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4113
4114 return 0;
4115 }
4116
4117 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4118 {
4119 int ret = 1;
4120 const char *vcfg = NULL;
4121
4122 (void)argc;
4123 (void)ctxt;
4124
4125 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4126 if (vcfg)
4127 {
4128 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4129 grub_env_set(args[1], vcfg);
4130 ret = 0;
4131 }
4132 else
4133 {
4134 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4135 }
4136
4137 grub_errno = 0;
4138 return ret;
4139 }
4140
4141
4142 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4143 {
4144 int id;
4145 grub_uint8_t zeroguid[16] = {0};
4146
4147 (void)argc;
4148 (void)ctxt;
4149
4150 id = (int)grub_strtoul(args[0], NULL, 10);
4151 grub_errno = 0;
4152
4153 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4154 {
4155 if (id >= 1 && id <= 128)
4156 {
4157 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4158 {
4159 return 0;
4160 }
4161 }
4162 }
4163 else
4164 {
4165 if (id >= 1 && id <= 4)
4166 {
4167 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4168 {
4169 return 0;
4170 }
4171 }
4172 }
4173
4174 return 1;
4175 }
4176
4177 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4178 {
4179 int rc = 1;
4180 char *device_name = NULL;
4181 grub_device_t dev = NULL;
4182 grub_fs_t fs = NULL;
4183 char *label = NULL;
4184
4185 (void)ctxt;
4186
4187 debug("get fs label for %s\n", args[0]);
4188
4189 if (argc != 2)
4190 {
4191 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4192 return 1;
4193 }
4194
4195 device_name = grub_file_get_device_name(args[0]);
4196 if (!device_name)
4197 {
4198 debug("grub_file_get_device_name failed, %s\n", args[0]);
4199 goto end;
4200 }
4201
4202 dev = grub_device_open(device_name);
4203 if (!dev)
4204 {
4205 debug("grub_device_open failed, %s\n", device_name);
4206 goto end;
4207 }
4208
4209 fs = grub_fs_probe(dev);
4210 if (NULL == fs || NULL == fs->fs_label)
4211 {
4212 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4213 goto end;
4214 }
4215
4216 fs->fs_label(dev, &label);
4217 if (label)
4218 {
4219 debug("label=<%s>\n", label);
4220 ventoy_set_env(args[1], label);
4221 grub_free(label);
4222 }
4223
4224 rc = 0;
4225
4226 end:
4227
4228 check_free(device_name, grub_free);
4229 check_free(dev, grub_device_close);
4230
4231 return rc;
4232 }
4233
4234 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4235 {
4236 if (!info->dir)
4237 {
4238 grub_snprintf((char *)data, 256, "%s", filename);
4239 return 1;
4240 }
4241
4242 return 0;
4243 }
4244
4245 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4246 {
4247 if (info->dir && filename && filename[0] != '.')
4248 {
4249 grub_snprintf((char *)data, 256, "%s", filename);
4250 return 1;
4251 }
4252
4253 return 0;
4254 }
4255
4256 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4257 {
4258 int rc = 1;
4259 char *device_name = NULL;
4260 grub_device_t dev = NULL;
4261 grub_fs_t fs = NULL;
4262 char name[256] ={0};
4263
4264 if (argc != 3)
4265 {
4266 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4267 return 1;
4268 }
4269
4270 device_name = grub_file_get_device_name(args[0]);
4271 if (!device_name)
4272 {
4273 debug("grub_file_get_device_name failed, %s\n", args[0]);
4274 goto end;
4275 }
4276
4277 dev = grub_device_open(device_name);
4278 if (!dev)
4279 {
4280 debug("grub_device_open failed, %s\n", device_name);
4281 goto end;
4282 }
4283
4284 fs = grub_fs_probe(dev);
4285 if (!fs)
4286 {
4287 debug("grub_fs_probe failed, %s\n", device_name);
4288 goto end;
4289 }
4290
4291 fs->fs_dir(dev, args[1], hook, name);
4292 if (name[0])
4293 {
4294 ventoy_set_env(args[2], name);
4295 }
4296
4297 rc = 0;
4298
4299 end:
4300
4301 check_free(device_name, grub_free);
4302 check_free(dev, grub_device_close);
4303
4304 return rc;
4305 }
4306
4307 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4308 {
4309 (void)ctxt;
4310 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4311 }
4312
4313 static grub_err_t ventoy_cmd_fs_enum_1st_dir(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_dir);
4317 }
4318
4319 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4320 {
4321 char c;
4322 char *pos = NULL;
4323 char *end = NULL;
4324
4325 (void)ctxt;
4326
4327 if (argc != 2)
4328 {
4329 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4330 return 1;
4331 }
4332
4333 for (pos = args[0]; *pos; pos++)
4334 {
4335 if (*pos == '.')
4336 {
4337 end = pos;
4338 }
4339 }
4340
4341 if (end)
4342 {
4343 c = *end;
4344 *end = 0;
4345 }
4346
4347 grub_env_set(args[1], args[0]);
4348
4349 if (end)
4350 {
4351 *end = c;
4352 }
4353
4354 return 0;
4355 }
4356
4357 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4358 {
4359 int i;
4360 int len;
4361 const char *buf;
4362
4363 (void)ctxt;
4364
4365 if (argc != 2)
4366 {
4367 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4368 return 1;
4369 }
4370
4371 buf = args[0];
4372 len = (int)grub_strlen(buf);
4373 for (i = len; i > 0; i--)
4374 {
4375 if (buf[i - 1] == '/')
4376 {
4377 grub_env_set(args[1], buf + i);
4378 return 0;
4379 }
4380 }
4381
4382 grub_env_set(args[1], buf);
4383
4384 return 0;
4385 }
4386
4387 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4388 {
4389 struct grub_video_mode_info info;
4390 char buf[32];
4391
4392 (void)ctxt;
4393 (void)argc;
4394 (void)args;
4395
4396 if (!g_video_mode_list)
4397 {
4398 ventoy_enum_video_mode();
4399 }
4400
4401 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4402 {
4403 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4404 }
4405 else
4406 {
4407 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4408 }
4409
4410 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4411
4412 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4413 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4414
4415 VENTOY_CMD_RETURN(0);
4416 }
4417
4418 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4419 {
4420 struct grub_video_mode_info info;
4421 char buf[32];
4422
4423 (void)ctxt;
4424 (void)argc;
4425 (void)args;
4426
4427 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4428 {
4429 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4430 }
4431 else
4432 {
4433 grub_snprintf(buf, sizeof(buf), "0x0x0");
4434 }
4435
4436 grub_env_set(args[0], buf);
4437
4438 VENTOY_CMD_RETURN(0);
4439 }
4440
4441 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4442 {
4443 int id;
4444 char buf[32];
4445
4446 (void)ctxt;
4447 (void)argc;
4448
4449 if (!g_video_mode_list)
4450 {
4451 return 0;
4452 }
4453
4454 id = (int)grub_strtoul(args[0], NULL, 10);
4455 if (id < g_video_mode_num)
4456 {
4457 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4458 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4459 }
4460
4461 grub_env_set(args[1], buf);
4462
4463 VENTOY_CMD_RETURN(0);
4464 }
4465
4466 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4467 {
4468 grub_uint32_t i;
4469 grub_uint32_t loadsector = 0;
4470 grub_file_t file;
4471 char value[32];
4472 grub_uint32_t boot_catlog = 0;
4473 grub_uint8_t buf[512];
4474
4475 (void)ctxt;
4476
4477 if (argc != 2)
4478 {
4479 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4480 return 1;
4481 }
4482
4483 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4484 if (!file)
4485 {
4486 debug("failed to open %s\n", args[0]);
4487 return 1;
4488 }
4489
4490 boot_catlog = ventoy_get_iso_boot_catlog(file);
4491 if (boot_catlog == 0)
4492 {
4493 debug("No bootcatlog found\n");
4494 grub_file_close(file);
4495 return 1;
4496 }
4497
4498 grub_memset(buf, 0, sizeof(buf));
4499 grub_file_seek(file, boot_catlog * 2048);
4500 grub_file_read(file, buf, sizeof(buf));
4501 grub_file_close(file);
4502
4503 for (i = 0; i < sizeof(buf); i += 32)
4504 {
4505 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4506 {
4507 if (buf[i + 32] == 0x88)
4508 {
4509 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4510 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4511 break;
4512 }
4513 }
4514 }
4515
4516 if (loadsector == 0)
4517 {
4518 debug("No EFI eltorito info found\n");
4519 return 1;
4520 }
4521
4522 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4523 grub_env_set(args[1], value);
4524 VENTOY_CMD_RETURN(0);
4525 }
4526
4527 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4528 {
4529 int curpos;
4530 int printlen;
4531 grub_size_t len;
4532 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4533
4534 if (pfsdir->initrd[0])
4535 {
4536 return 1;
4537 }
4538
4539 curpos = pfsdir->curpos;
4540 len = grub_strlen(filename);
4541
4542 if (info->dir)
4543 {
4544 if ((len == 1 && filename[0] == '.') ||
4545 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4546 {
4547 return 0;
4548 }
4549
4550 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4551 pfsdir->dircnt++;
4552
4553 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4554 pfsdir->curpos = curpos + printlen;
4555 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4556 pfsdir->curpos = curpos;
4557 pfsdir->fullpath[curpos] = 0;
4558 }
4559 else
4560 {
4561 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4562 pfsdir->filecnt++;
4563
4564 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4565 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4566 {
4567 if (info->size > 32 * VTOY_SIZE_1MB)
4568 {
4569 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4570 return 1;
4571 }
4572 }
4573 }
4574
4575 return 0;
4576 }
4577
4578 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4579 {
4580 int i;
4581 char *pos = NULL;
4582 char *device_name = NULL;
4583 grub_device_t dev = NULL;
4584 grub_fs_t fs = NULL;
4585 replace_fs_dir *pfsdir = NULL;
4586
4587 (void)ctxt;
4588
4589 if (argc != 2)
4590 {
4591 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4592 return 1;
4593 }
4594
4595 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4596 if (!pfsdir)
4597 {
4598 return 1;
4599 }
4600
4601 device_name = grub_file_get_device_name(args[0]);
4602 if (!device_name)
4603 {
4604 goto fail;
4605 }
4606
4607 dev = grub_device_open(device_name);
4608 if (!dev)
4609 {
4610 goto fail;
4611 }
4612
4613 fs = grub_fs_probe(dev);
4614 if (!fs)
4615 {
4616 goto fail;
4617 }
4618
4619 pfsdir->dev = dev;
4620 pfsdir->fs = fs;
4621 pfsdir->curpos = 1;
4622 pfsdir->fullpath[0] = '/';
4623 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4624
4625 if (pfsdir->initrd[0])
4626 {
4627 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4628
4629 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4630 {
4631 if (pfsdir->initrd[i] == '/')
4632 {
4633 pfsdir->initrd[i] = '\\';
4634 }
4635 }
4636
4637 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4638 grub_env_set(args[1], pos);
4639 }
4640 else
4641 {
4642 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4643 }
4644
4645 fail:
4646
4647 grub_check_free(pfsdir);
4648 grub_check_free(device_name);
4649 check_free(dev, grub_device_close);
4650
4651 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4652 }
4653
4654 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4655 {
4656 const char *pager = NULL;
4657
4658 (void)ctxt;
4659 (void)argc;
4660 (void)args;
4661
4662 pager = grub_env_get("pager");
4663 if (NULL == pager)
4664 {
4665 g_pager_flag = 1;
4666 grub_env_set("pager", "1");
4667 }
4668 else if (pager[0] == '1')
4669 {
4670 g_pager_flag = 0;
4671 }
4672 else
4673 {
4674 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
4675 g_pager_flag = 2;
4676 grub_env_set("pager", "1");
4677 }
4678
4679 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4680 }
4681
4682 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4683 {
4684 (void)ctxt;
4685 (void)argc;
4686 (void)args;
4687
4688 if (g_pager_flag == 1)
4689 {
4690 grub_env_unset("pager");
4691 }
4692 else if (g_pager_flag == 2)
4693 {
4694 grub_env_set("pager", g_old_pager);
4695 }
4696
4697 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4698 }
4699
4700 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4701 {
4702 if (g_json_case_mis_path[0])
4703 {
4704 return 1;
4705 }
4706
4707 if (0 == info->dir && grub_strncasecmp(filename, "ventoy.json", 11) == 0)
4708 {
4709 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
4710 return 1;
4711 }
4712 return 0;
4713 }
4714
4715 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4716 {
4717 char path[16];
4718 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
4719
4720 if (g_json_case_mis_path[0])
4721 {
4722 return 1;
4723 }
4724
4725 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
4726 {
4727 if (grub_strncasecmp(filename, "ventoy", 6) == 0)
4728 {
4729 grub_snprintf(path, sizeof(path), "/%s", filename);
4730 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
4731 if (g_json_case_mis_path[0])
4732 {
4733 return 1;
4734 }
4735 }
4736 }
4737
4738 return 0;
4739 }
4740
4741 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
4742 {
4743 int fstype = 0;
4744 char *device_name = NULL;
4745 grub_device_t dev = NULL;
4746 grub_fs_t fs = NULL;
4747 chk_case_fs_dir fs_dir;
4748
4749 (void)ctxt;
4750 (void)argc;
4751 (void)args;
4752
4753 device_name = grub_file_get_device_name(args[0]);
4754 if (!device_name)
4755 {
4756 goto out;
4757 }
4758
4759 dev = grub_device_open(device_name);
4760 if (!dev)
4761 {
4762 goto out;
4763 }
4764
4765 fs = grub_fs_probe(dev);
4766 if (!fs)
4767 {
4768 goto out;
4769 }
4770
4771 fstype = ventoy_get_fs_type(fs->name);
4772 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
4773 {
4774 goto out;
4775 }
4776
4777 g_json_case_mis_path[0] = 0;
4778 fs_dir.dev = dev;
4779 fs_dir.fs = fs;
4780 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
4781
4782 if (g_json_case_mis_path[0])
4783 {
4784 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
4785 }
4786
4787 out:
4788
4789 grub_check_free(device_name);
4790 check_free(dev, grub_device_close);
4791
4792 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4793 }
4794
4795 int ventoy_env_init(void)
4796 {
4797 char buf[64];
4798
4799 grub_env_set("vtdebug_flag", "");
4800
4801 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4802 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4803 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4804 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4805
4806 ventoy_filt_register(0, ventoy_wrapper_open);
4807
4808 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4809 if (g_grub_param)
4810 {
4811 g_grub_param->grub_env_get = grub_env_get;
4812 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4813 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4814 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4815 grub_env_set("env_param", buf);
4816 grub_env_set("ventoy_env_param", buf);
4817
4818 grub_env_export("env_param");
4819 grub_env_export("ventoy_env_param");
4820 }
4821
4822 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
4823 grub_env_set("vtoy_winpeshl_ini_addr", buf);
4824
4825 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
4826 grub_env_set("vtoy_winpeshl_ini_size", buf);
4827
4828 grub_env_export("vtoy_winpeshl_ini_addr");
4829 grub_env_export("vtoy_winpeshl_ini_size");
4830
4831 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
4832 grub_env_set("vtoy_chain_file_size", buf);
4833 grub_env_export("vtoy_chain_file_size");
4834
4835 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
4836 grub_env_set("vtoy_chain_file_read", buf);
4837 grub_env_export("vtoy_chain_file_read");
4838
4839 return 0;
4840 }
4841
4842 static cmd_para ventoy_cmds[] =
4843 {
4844 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4845 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4846 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4847 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4848 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4849 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4850 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4851 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4852 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4853 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4854 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4855 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4856 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4857 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4858 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
4859 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4860 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4861 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4862 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4863 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4864 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4865 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4866 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4867 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4868
4869 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4870 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4871 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4872 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4873 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4874 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4875 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4876
4877 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4878 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4879 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4880 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4881 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
4882 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4883 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4884 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4885 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4886 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4887
4888
4889 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4890 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4891 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4892 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4893 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4894 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4895 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4896 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4897 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4898 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4899 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4900
4901 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4902 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
4903 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4904 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4905 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4906 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4907 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4908
4909 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4910 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4911 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4912 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4913 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4914 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4915 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4916 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4917 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4918 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4919
4920 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4921 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4922 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
4923 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4924 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4925 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4926 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4927 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4928 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4929
4930 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4931 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
4932 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4933 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4934
4935
4936 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4937 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4938 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4939
4940 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4941 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4942 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4943
4944
4945 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4946 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4947 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4948 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4949 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
4950 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4951 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4952 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4953 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4954 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4955 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4956
4957 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4958 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4959 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4960 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4961 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
4962 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
4963 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
4964 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
4965 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
4966 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
4967
4968 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
4969 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
4970 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
4971 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
4972 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
4973 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
4974 };
4975
4976 int ventoy_register_all_cmd(void)
4977 {
4978 grub_uint32_t i;
4979 cmd_para *cur = NULL;
4980
4981 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4982 {
4983 cur = ventoy_cmds + i;
4984 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4985 cur->summary, cur->description, cur->parser);
4986 }
4987
4988 return 0;
4989 }
4990
4991 int ventoy_unregister_all_cmd(void)
4992 {
4993 grub_uint32_t i;
4994
4995 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4996 {
4997 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4998 }
4999
5000 return 0;
5001 }
5002
5003