]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
b7e7ce0a00ceb15bae7d969fd11b4b72987bbdcb
[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 const menu_tip *tip;
1566 img_iterator_node *tmp;
1567 img_iterator_node *new_node;
1568 img_iterator_node *node = (img_iterator_node *)data;
1569
1570 if (g_enumerate_time_checked == 0)
1571 {
1572 g_enumerate_finish_time_ms = grub_get_time_ms();
1573 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1574 {
1575 grub_cls();
1576 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1577 grub_refresh();
1578 g_enumerate_time_checked = 1;
1579 }
1580 }
1581
1582 len = grub_strlen(filename);
1583
1584 if (info->dir)
1585 {
1586 if (node->level + 1 > g_img_max_search_level)
1587 {
1588 return 0;
1589 }
1590
1591 if ((len == 1 && filename[0] == '.') ||
1592 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1593 {
1594 return 0;
1595 }
1596
1597 if (!ventoy_img_name_valid(filename, len))
1598 {
1599 return 0;
1600 }
1601
1602 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1603 {
1604 return 0;
1605 }
1606
1607 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1608 {
1609 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1610 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1611 if (index == 0)
1612 {
1613 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1614 return 0;
1615 }
1616 }
1617
1618 new_node = grub_zalloc(sizeof(img_iterator_node));
1619 if (new_node)
1620 {
1621 new_node->level = node->level + 1;
1622 new_node->plugin_list_index = index;
1623 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1624
1625 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1626 if (ignore)
1627 {
1628 debug("Directory %s ignored...\n", new_node->dir);
1629 grub_free(new_node);
1630 return 0;
1631 }
1632
1633 new_node->tail = node->tail;
1634
1635 new_node->parent = node;
1636 if (!node->firstchild)
1637 {
1638 node->firstchild = new_node;
1639 }
1640
1641 if (g_img_iterator_tail)
1642 {
1643 g_img_iterator_tail->next = new_node;
1644 g_img_iterator_tail = new_node;
1645 }
1646 else
1647 {
1648 g_img_iterator_head.next = new_node;
1649 g_img_iterator_tail = new_node;
1650 }
1651 }
1652 }
1653 else
1654 {
1655 debug("Find a file %s\n", filename);
1656 if (len < 4)
1657 {
1658 return 0;
1659 }
1660
1661 if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso"))
1662 {
1663 type = img_type_iso;
1664 }
1665 else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1666 {
1667 type = img_type_wim;
1668 }
1669 else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1670 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1671 {
1672 type = img_type_vhd;
1673 }
1674 #ifdef GRUB_MACHINE_EFI
1675 else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi"))
1676 {
1677 type = img_type_efi;
1678 }
1679 #endif
1680 else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img"))
1681 {
1682 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1683 {
1684 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1685 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1686 {
1687 return 0;
1688 }
1689 }
1690 type = img_type_img;
1691 }
1692 else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1693 {
1694 type = img_type_vtoy;
1695 }
1696 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1697 {
1698 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1699 {
1700 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1701 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1702 }
1703 return 0;
1704 }
1705 else
1706 {
1707 return 0;
1708 }
1709
1710 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1711 {
1712 return 0;
1713 }
1714
1715 if (g_plugin_image_list)
1716 {
1717 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1718 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1719 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1720 {
1721 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1722 return 0;
1723 }
1724 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
1725 {
1726 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index);
1727 return 0;
1728 }
1729 }
1730
1731 img = grub_zalloc(sizeof(img_info));
1732 if (img)
1733 {
1734 img->type = type;
1735 img->plugin_list_index = index;
1736 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1737
1738 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1739
1740 img->size = info->size;
1741 if (0 == img->size)
1742 {
1743 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1744 }
1745
1746 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1747 {
1748 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1749 grub_free(img);
1750 return 0;
1751 }
1752
1753 if (g_ventoy_img_list)
1754 {
1755 tail = *(node->tail);
1756 img->prev = tail;
1757 tail->next = img;
1758 }
1759 else
1760 {
1761 g_ventoy_img_list = img;
1762 }
1763
1764 img->id = g_ventoy_img_count;
1765 img->parent = node;
1766 if (node && NULL == node->firstiso)
1767 {
1768 node->firstiso = img;
1769 }
1770
1771 node->isocnt++;
1772 tmp = node->parent;
1773 while (tmp)
1774 {
1775 tmp->isocnt++;
1776 tmp = tmp->parent;
1777 }
1778
1779 *((img_info **)(node->tail)) = img;
1780 g_ventoy_img_count++;
1781
1782 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1783
1784 tip = ventoy_plugin_get_menu_tip(img->path);
1785 if (tip)
1786 {
1787 img->tip1 = tip->tip1;
1788 img->tip2 = tip->tip2;
1789 }
1790
1791 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path);
1792 if (!img->class)
1793 {
1794 img->class = g_menu_class[type];
1795 }
1796 img->menu_prefix = g_menu_prefix[type];
1797
1798 if (img_type_iso == type)
1799 {
1800 if (ventoy_plugin_check_memdisk(img->path))
1801 {
1802 img->menu_prefix = "miso";
1803 }
1804 }
1805
1806 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1807 }
1808 }
1809
1810 return 0;
1811 }
1812
1813 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1814 {
1815 int len = GRUB_UINT_MAX;
1816 const char *value = NULL;
1817 char name[32] = {0};
1818 char plat[32] = {0};
1819 char guidstr[32] = {0};
1820 ventoy_guid guid = VENTOY_GUID;
1821 const char *fmt1 = NULL;
1822 const char *fmt2 = NULL;
1823 const char *fmt3 = NULL;
1824 grub_uint32_t *puint = (grub_uint32_t *)name;
1825 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1826 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1827 const char fmtcode[]={
1828 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1829 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1830 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1831 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1832 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1833 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1834 };
1835
1836 grub_memset(name, 0, sizeof(name));
1837 puint[0] = grub_swap_bytes32(0x56454e54);
1838 puint[3] = grub_swap_bytes32(0x4f4e0000);
1839 puint[2] = grub_swap_bytes32(0x45525349);
1840 puint[1] = grub_swap_bytes32(0x4f595f56);
1841 value = ventoy_get_env(name);
1842
1843 grub_memset(name, 0, sizeof(name));
1844 puint[1] = grub_swap_bytes32(0x5f544f50);
1845 puint[0] = grub_swap_bytes32(0x56544c45);
1846 fmt1 = ventoy_get_env(name);
1847 if (!fmt1)
1848 {
1849 fmt1 = fmtdata;
1850 }
1851
1852 grub_memset(name, 0, sizeof(name));
1853 puint[1] = grub_swap_bytes32(0x5f4c4654);
1854 puint[0] = grub_swap_bytes32(0x56544c45);
1855 fmt2 = ventoy_get_env(name);
1856
1857 grub_memset(name, 0, sizeof(name));
1858 puint[1] = grub_swap_bytes32(0x5f434c52);
1859 puint[0] = grub_swap_bytes32(0x56544c45);
1860 fmt3 = ventoy_get_env(name);
1861
1862 grub_memcpy(guidstr, &guid, sizeof(guid));
1863
1864 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1865
1866 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1867 #pragma GCC diagnostic push
1868 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1869 len = grub_snprintf(buffer, buflen, fmtcode,
1870 fmt1 ? fmt1 : fmtdata,
1871 fmt2 ? fmt2 : fmtdata + 4,
1872 value ? value : "", plat, guidstr,
1873 fmt3 ? fmt3 : fmtdata + 6);
1874 #pragma GCC diagnostic pop
1875
1876 grub_memset(name, 0, sizeof(name));
1877 puint[0] = grub_swap_bytes32(0x76746f79);
1878 puint[2] = grub_swap_bytes32(0x656e7365);
1879 puint[1] = grub_swap_bytes32(0x5f6c6963);
1880 ventoy_set_env(name, guidstr);
1881
1882 return len;
1883 }
1884
1885 int ventoy_check_password(const vtoy_password *pwd, int retry)
1886 {
1887 int offset;
1888 char input[256];
1889 grub_uint8_t md5[16];
1890
1891 while (retry--)
1892 {
1893 grub_memset(input, 0, sizeof(input));
1894
1895 grub_printf("Enter password: ");
1896 grub_refresh();
1897
1898 if (pwd->type == VTOY_PASSWORD_TXT)
1899 {
1900 grub_password_get(input, 128);
1901 if (grub_strcmp(pwd->text, input) == 0)
1902 {
1903 return 0;
1904 }
1905 }
1906 else if (pwd->type == VTOY_PASSWORD_MD5)
1907 {
1908 grub_password_get(input, 128);
1909 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1910 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1911 {
1912 return 0;
1913 }
1914 }
1915 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1916 {
1917 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1918 grub_password_get(input + offset, 128);
1919
1920 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1921 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1922 {
1923 return 0;
1924 }
1925 }
1926
1927 grub_printf("Invalid password!\n\n");
1928 grub_refresh();
1929 }
1930
1931 return 1;
1932 }
1933
1934 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1935 {
1936 img_info *minimg = NULL;
1937 img_info *img = (img_info *)(node->firstiso);
1938
1939 while (img && (img_iterator_node *)(img->parent) == node)
1940 {
1941 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1942 {
1943 minimg = img;
1944 }
1945 img = img->next;
1946 }
1947
1948 if (minimg)
1949 {
1950 minimg->select = 1;
1951 }
1952
1953 return minimg;
1954 }
1955
1956 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1957 {
1958 img_iterator_node *Minchild = NULL;
1959 img_iterator_node *child = node->firstchild;
1960
1961 while (child && child->parent == node)
1962 {
1963 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1964 {
1965 Minchild = child;
1966 }
1967 child = child->next;
1968 }
1969
1970 if (Minchild)
1971 {
1972 Minchild->select = 1;
1973 }
1974
1975 return Minchild;
1976 }
1977
1978 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1979 {
1980 int offset = 1;
1981 img_info *img = NULL;
1982 const char *dir_class = NULL;
1983 const char *dir_alias = NULL;
1984 img_iterator_node *child = NULL;
1985
1986 if (node->isocnt == 0 || node->done == 1)
1987 {
1988 return 0;
1989 }
1990
1991 if (node->parent && node->parent->dirlen < node->dirlen)
1992 {
1993 offset = node->parent->dirlen;
1994 }
1995
1996 if (node == &g_img_iterator_head)
1997 {
1998 if (g_default_menu_mode == 0)
1999 {
2000 if (g_tree_view_menu_style == 0)
2001 {
2002 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2003 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2004 " echo 'return ...' \n"
2005 "}\n", "<--");
2006 }
2007 else
2008 {
2009 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2010 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2011 " echo '%s ...' \n"
2012 "}\n", "return");
2013 }
2014 }
2015 }
2016 else
2017 {
2018 node->dir[node->dirlen - 1] = 0;
2019 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2020 if (!dir_class)
2021 {
2022 dir_class = "vtoydir";
2023 }
2024
2025 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2026 if (dir_alias)
2027 {
2028 if (g_tree_view_menu_style == 0)
2029 {
2030 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2031 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2032 "DIR", dir_alias, dir_class, node->dir + offset);
2033 }
2034 else
2035 {
2036 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2037 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2038 dir_alias, dir_class, node->dir + offset);
2039 }
2040 }
2041 else
2042 {
2043 dir_alias = node->dir + offset;
2044
2045 if (g_tree_view_menu_style == 0)
2046 {
2047 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2048 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2049 "DIR", dir_alias, dir_class, node->dir + offset);
2050 }
2051 else
2052 {
2053 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2054 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2055 dir_alias, dir_class, node->dir + offset);
2056 }
2057 }
2058
2059 if (g_tree_view_menu_style == 0)
2060 {
2061 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2062 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
2063 " echo 'return ...' \n"
2064 "}\n", "<--");
2065 }
2066 else
2067 {
2068 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2069 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
2070 " echo '%s ...' \n"
2071 "}\n", "return");
2072 }
2073 }
2074
2075 while ((child = ventoy_get_min_child(node)) != NULL)
2076 {
2077 ventoy_dynamic_tree_menu(child);
2078 }
2079
2080 while ((img = ventoy_get_min_iso(node)) != NULL)
2081 {
2082 if (g_tree_view_menu_style == 0)
2083 {
2084 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2085 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2086 " %s_%s \n"
2087 "}\n",
2088 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2089 img->unsupport ? "[***********] " : "",
2090 img->alias ? img->alias : img->name, img->class, img,
2091 img->menu_prefix,
2092 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2093 }
2094 else
2095 {
2096 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2097 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2098 " %s_%s \n"
2099 "}\n",
2100 img->unsupport ? "[***********] " : "",
2101 img->alias ? img->alias : img->name, img->class, img,
2102 img->menu_prefix,
2103 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2104 }
2105 }
2106
2107 if (node != &g_img_iterator_head)
2108 {
2109 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
2110 }
2111
2112 node->done = 1;
2113 return 0;
2114 }
2115
2116 static int ventoy_set_default_menu(void)
2117 {
2118 int img_len = 0;
2119 char *pos = NULL;
2120 char *end = NULL;
2121 char *def = NULL;
2122 const char *strdata = NULL;
2123 img_info *cur = NULL;
2124 img_info *default_node = NULL;
2125 const char *default_image = NULL;
2126
2127 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2128 if (default_image && default_image[0] == '/')
2129 {
2130 img_len = grub_strlen(default_image);
2131
2132 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2133 {
2134 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2135 {
2136 default_node = cur;
2137 break;
2138 }
2139 }
2140
2141 if (!default_node)
2142 {
2143 return 1;
2144 }
2145
2146 if (0 == g_default_menu_mode)
2147 {
2148 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2149 }
2150 else
2151 {
2152 def = grub_strdup(default_image);
2153 if (!def)
2154 {
2155 return 1;
2156 }
2157
2158 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2159
2160 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2161 if (strdata && strdata[0] == '/')
2162 {
2163 pos = def + grub_strlen(strdata);
2164 if (*pos == '/')
2165 {
2166 pos++;
2167 }
2168 }
2169 else
2170 {
2171 pos = def + 1;
2172 }
2173
2174 while ((end = grub_strchr(pos, '/')) != NULL)
2175 {
2176 *end = 0;
2177 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2178 pos = end + 1;
2179 }
2180
2181 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2182 grub_free(def);
2183 }
2184 }
2185
2186 return 0;
2187 }
2188
2189 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2190 {
2191 img_info *next = NULL;
2192 img_info *cur = g_ventoy_img_list;
2193
2194 (void)ctxt;
2195 (void)argc;
2196 (void)args;
2197
2198 while (cur)
2199 {
2200 next = cur->next;
2201 grub_free(cur);
2202 cur = next;
2203 }
2204
2205 g_ventoy_img_list = NULL;
2206 g_ventoy_img_count = 0;
2207
2208 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2209 }
2210
2211 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2212 {
2213 long img_id = 0;
2214 img_info *cur = g_ventoy_img_list;
2215
2216 (void)ctxt;
2217
2218 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2219 {
2220 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2221 }
2222
2223 img_id = grub_strtol(args[0], NULL, 10);
2224 if (img_id >= g_ventoy_img_count)
2225 {
2226 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2227 }
2228
2229 debug("Find image %ld name \n", img_id);
2230
2231 while (cur && img_id > 0)
2232 {
2233 img_id--;
2234 cur = cur->next;
2235 }
2236
2237 if (!cur)
2238 {
2239 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2240 }
2241
2242 debug("image name is %s\n", cur->name);
2243
2244 grub_env_set(args[1], cur->name);
2245
2246 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2247 }
2248
2249 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2250 {
2251 int len = 0;
2252 char id[32] = {0};
2253 img_info *cur = g_ventoy_img_list;
2254
2255 (void)ctxt;
2256
2257 if (argc != 1)
2258 {
2259 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2260 }
2261
2262 len = (int)grub_strlen(args[0]);
2263
2264 while (cur)
2265 {
2266 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2267 {
2268 break;
2269 }
2270 cur = cur->next;
2271 }
2272
2273 if (!cur)
2274 {
2275 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2276 }
2277
2278 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2279 grub_env_set("chosen", id);
2280 grub_env_export("chosen");
2281
2282 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2283 }
2284
2285 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2286 {
2287 char value[32];
2288 char *pos = NULL;
2289 const char *id = NULL;
2290 img_info *cur = NULL;
2291
2292 (void)ctxt;
2293
2294 if (argc < 1 || argc > 2)
2295 {
2296 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2297 }
2298
2299 id = grub_env_get("chosen");
2300
2301 pos = grub_strstr(id, "VID_");
2302 if (pos)
2303 {
2304 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2305 }
2306 else
2307 {
2308 cur = g_ventoy_img_list;
2309 }
2310
2311 if (!cur)
2312 {
2313 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2314 }
2315
2316 grub_env_set(args[0], cur->path);
2317
2318 if (argc > 1)
2319 {
2320 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2321 grub_env_set(args[1], value);
2322 }
2323
2324 g_svd_replace_offset = 0;
2325
2326 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2327 }
2328
2329
2330 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2331 {
2332 int len;
2333 grub_fs_t fs;
2334 grub_device_t dev = NULL;
2335 img_info *cur = NULL;
2336 img_info *tail = NULL;
2337 img_info *min = NULL;
2338 img_info *head = NULL;
2339 const char *strdata = NULL;
2340 char *device_name = NULL;
2341 char buf[32];
2342 img_iterator_node *node = NULL;
2343 img_iterator_node *tmp = NULL;
2344
2345 (void)ctxt;
2346
2347 if (argc != 2)
2348 {
2349 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2350 }
2351
2352 if (g_ventoy_img_list || g_ventoy_img_count)
2353 {
2354 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2355 }
2356
2357 VTOY_CMD_CHECK(1);
2358
2359 g_enumerate_time_checked = 0;
2360 g_enumerate_start_time_ms = grub_get_time_ms();
2361
2362 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2363 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2364 {
2365 g_filt_dot_underscore_file = 1;
2366 }
2367
2368 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2369 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2370 {
2371 g_sort_case_sensitive = 1;
2372 }
2373
2374 device_name = grub_file_get_device_name(args[0]);
2375 if (!device_name)
2376 {
2377 goto fail;
2378 }
2379
2380 g_enum_dev = dev = grub_device_open(device_name);
2381 if (!dev)
2382 {
2383 goto fail;
2384 }
2385
2386 g_enum_fs = fs = grub_fs_probe(dev);
2387 if (!fs)
2388 {
2389 goto fail;
2390 }
2391
2392 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2393 {
2394 debug("unsupported fs:<%s>\n", fs->name);
2395 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2396 goto fail;
2397 }
2398
2399 ventoy_set_env("vtoy_iso_fs", fs->name);
2400
2401 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2402 if (strdata && strdata[0] == '1')
2403 {
2404 g_default_menu_mode = 1;
2405 }
2406
2407 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2408
2409 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2410
2411 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2412 if (strdata && strdata[0] == '/')
2413 {
2414 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2415 if (g_img_iterator_head.dir[len - 1] != '/')
2416 {
2417 g_img_iterator_head.dir[len++] = '/';
2418 }
2419 g_img_iterator_head.dirlen = len;
2420 }
2421 else
2422 {
2423 g_img_iterator_head.dirlen = 1;
2424 grub_strcpy(g_img_iterator_head.dir, "/");
2425 }
2426
2427 g_img_iterator_head.tail = &tail;
2428
2429 if (g_img_max_search_level < 0)
2430 {
2431 g_img_max_search_level = GRUB_INT_MAX;
2432 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2433 if (strdata && ventoy_is_decimal(strdata))
2434 {
2435 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2436 }
2437 }
2438
2439 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2440 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2441 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2442 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2443 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2444 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2445
2446 for (node = &g_img_iterator_head; node; node = node->next)
2447 {
2448 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2449 }
2450
2451 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2452 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2453 {
2454 g_tree_view_menu_style = 1;
2455 }
2456
2457 ventoy_set_default_menu();
2458
2459 for (node = &g_img_iterator_head; node; node = node->next)
2460 {
2461 ventoy_dynamic_tree_menu(node);
2462 }
2463
2464 /* free node */
2465 node = g_img_iterator_head.next;
2466 while (node)
2467 {
2468 tmp = node->next;
2469 grub_free(node);
2470 node = tmp;
2471 }
2472
2473 /* sort image list by image name */
2474 while (g_ventoy_img_list)
2475 {
2476 min = g_ventoy_img_list;
2477 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2478 {
2479 if (ventoy_cmp_img(min, cur) > 0)
2480 {
2481 min = cur;
2482 }
2483 }
2484
2485 if (min->prev)
2486 {
2487 min->prev->next = min->next;
2488 }
2489
2490 if (min->next)
2491 {
2492 min->next->prev = min->prev;
2493 }
2494
2495 if (min == g_ventoy_img_list)
2496 {
2497 g_ventoy_img_list = min->next;
2498 }
2499
2500 if (head == NULL)
2501 {
2502 head = tail = min;
2503 min->prev = NULL;
2504 min->next = NULL;
2505 }
2506 else
2507 {
2508 tail->next = min;
2509 min->prev = tail;
2510 min->next = NULL;
2511 tail = min;
2512 }
2513 }
2514
2515 g_ventoy_img_list = head;
2516
2517 if (g_default_menu_mode == 1)
2518 {
2519 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2520 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2521 " echo 'return ...' \n"
2522 "}\n", "<--");
2523 }
2524
2525 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2526 {
2527 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2528 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2529 " %s_%s \n"
2530 "}\n",
2531 cur->unsupport ? "[***********] " : "",
2532 cur->alias ? cur->alias : cur->name, cur->class, cur,
2533 cur->menu_prefix,
2534 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2535 }
2536
2537 g_tree_script_buf[g_tree_script_pos] = 0;
2538 g_list_script_buf[g_list_script_pos] = 0;
2539
2540 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2541 grub_env_set(args[1], buf);
2542
2543 fail:
2544
2545 check_free(device_name, grub_free);
2546 check_free(dev, grub_device_close);
2547
2548 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2549 }
2550
2551 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2552 {
2553 grub_disk_t disk;
2554 char *device_name;
2555 char *pos;
2556 char *pos2;
2557
2558 device_name = grub_file_get_device_name(filename);
2559 if (!device_name)
2560 {
2561 return 1;
2562 }
2563
2564 pos = device_name;
2565 if (pos[0] == '(')
2566 {
2567 pos++;
2568 }
2569
2570 pos2 = grub_strstr(pos, ",");
2571 if (!pos2)
2572 {
2573 pos2 = grub_strstr(pos, ")");
2574 }
2575
2576 if (pos2)
2577 {
2578 *pos2 = 0;
2579 }
2580
2581 disk = grub_disk_open(pos);
2582 if (disk)
2583 {
2584 grub_disk_read(disk, 0, 0x180, 16, guid);
2585 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2586 grub_disk_close(disk);
2587 }
2588 else
2589 {
2590 return 1;
2591 }
2592
2593 grub_free(device_name);
2594 return 0;
2595 }
2596
2597 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2598 {
2599 eltorito_descriptor desc;
2600
2601 grub_memset(&desc, 0, sizeof(desc));
2602 grub_file_seek(file, 17 * 2048);
2603 grub_file_read(file, &desc, sizeof(desc));
2604
2605 if (desc.type != 0 || desc.version != 1)
2606 {
2607 return 0;
2608 }
2609
2610 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2611 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2612 {
2613 return 0;
2614 }
2615
2616 return desc.sector;
2617 }
2618
2619 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2620 {
2621 int i;
2622 int x86count = 0;
2623 grub_uint8_t buf[512];
2624 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2625
2626 grub_file_seek(file, sector * 2048);
2627 grub_file_read(file, buf, sizeof(buf));
2628
2629 if (buf[0] == 0x01 && buf[1] == 0xEF)
2630 {
2631 debug("%s efi eltorito in Validation Entry\n", file->name);
2632 return 1;
2633 }
2634
2635 if (buf[0] == 0x01 && buf[1] == 0x00)
2636 {
2637 x86count++;
2638 }
2639
2640 for (i = 64; i < (int)sizeof(buf); i += 32)
2641 {
2642 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2643 {
2644 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2645 return 1;
2646 }
2647
2648 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2649 {
2650 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2651 return 1;
2652 }
2653 }
2654
2655 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2656 {
2657 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2658 {
2659 if (buf[36] == parttype[i])
2660 {
2661 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2662 return 1;
2663 }
2664 }
2665 }
2666
2667 debug("%s does not contain efi eltorito\n", file->name);
2668 return 0;
2669 }
2670
2671 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2672 {
2673 char *pos;
2674 const char *fs = NULL;
2675 const char *cdprompt = NULL;
2676 grub_uint32_t i;
2677 grub_uint8_t chksum = 0;
2678 grub_disk_t disk;
2679
2680 disk = file->device->disk;
2681 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2682
2683 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2684 param->vtoy_disk_part_id = disk->partition->number + 1;
2685 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2686
2687 pos = grub_strstr(file->name, "/");
2688 if (!pos)
2689 {
2690 pos = file->name;
2691 }
2692
2693 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2694
2695 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2696
2697 param->vtoy_img_size = file->size;
2698
2699 param->vtoy_reserved[0] = g_ventoy_break_level;
2700 param->vtoy_reserved[1] = g_ventoy_debug_level;
2701
2702 param->vtoy_reserved[2] = g_ventoy_chain_type;
2703
2704 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2705 param->vtoy_reserved[4] = 0;
2706 if (g_ventoy_chain_type == 1) /* Windows */
2707 {
2708 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2709 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2710 {
2711 param->vtoy_reserved[4] = 1;
2712 }
2713 }
2714
2715 fs = ventoy_get_env("ventoy_fs_probe");
2716 if (fs && grub_strcmp(fs, "udf") == 0)
2717 {
2718 param->vtoy_reserved[3] = 1;
2719 }
2720
2721 /* calculate checksum */
2722 for (i = 0; i < sizeof(ventoy_os_param); i++)
2723 {
2724 chksum += *((grub_uint8_t *)param + i);
2725 }
2726 param->chksum = (grub_uint8_t)(0x100 - chksum);
2727
2728 return;
2729 }
2730
2731 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2732 {
2733 grub_uint32_t i = 0;
2734 grub_uint64_t total = 0;
2735 grub_uint64_t fileblk = 0;
2736 ventoy_img_chunk *chunk = NULL;
2737
2738 for (i = 0; i < chunklist->cur_chunk; i++)
2739 {
2740 chunk = chunklist->chunk + i;
2741
2742 if (chunk->disk_start_sector <= start)
2743 {
2744 debug("%u disk start invalid %lu\n", i, (ulong)start);
2745 return 1;
2746 }
2747
2748 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2749 }
2750
2751 fileblk = (file->size + 511) / 512;
2752
2753 if (total != fileblk)
2754 {
2755 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
2756 if ((file->size % 512) && (total + 1 == fileblk))
2757 {
2758 debug("maybe img file to be processed.\n");
2759 return 0;
2760 }
2761
2762 return 1;
2763 }
2764
2765 return 0;
2766 }
2767
2768 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2769 {
2770 int fs_type;
2771 int len;
2772 grub_uint32_t i = 0;
2773 grub_uint32_t sector = 0;
2774 grub_uint32_t count = 0;
2775 grub_off_t size = 0;
2776 grub_off_t read = 0;
2777
2778 fs_type = ventoy_get_fs_type(file->fs->name);
2779 if (fs_type == ventoy_fs_exfat)
2780 {
2781 grub_fat_get_file_chunk(start, file, chunklist);
2782 }
2783 else if (fs_type == ventoy_fs_ext)
2784 {
2785 grub_ext_get_file_chunk(start, file, chunklist);
2786 }
2787 else
2788 {
2789 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2790 file->read_hook_data = chunklist;
2791
2792 for (size = file->size; size > 0; size -= read)
2793 {
2794 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2795 grub_file_read(file, NULL, read);
2796 }
2797
2798 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2799 {
2800 chunklist->chunk[i].disk_start_sector += start;
2801 chunklist->chunk[i].disk_end_sector += start;
2802 }
2803
2804 if (ventoy_fs_udf == fs_type)
2805 {
2806 for (i = 0; i < chunklist->cur_chunk; i++)
2807 {
2808 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2809 chunklist->chunk[i].img_start_sector = sector;
2810 chunklist->chunk[i].img_end_sector = sector + count - 1;
2811 sector += count;
2812 }
2813 }
2814 }
2815
2816 len = (int)grub_strlen(file->name);
2817 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2818 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2819 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2820 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2821 {
2822 for (i = 0; i < chunklist->cur_chunk; i++)
2823 {
2824 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2825 if (count < 4)
2826 {
2827 count = 1;
2828 }
2829 else
2830 {
2831 count >>= 2;
2832 }
2833
2834 chunklist->chunk[i].img_start_sector = sector;
2835 chunklist->chunk[i].img_end_sector = sector + count - 1;
2836 sector += count;
2837 }
2838 }
2839
2840 return 0;
2841 }
2842
2843 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2844 {
2845 int rc;
2846 grub_file_t file;
2847 grub_disk_addr_t start;
2848
2849 (void)ctxt;
2850 (void)argc;
2851
2852 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2853 if (!file)
2854 {
2855 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2856 }
2857
2858 g_conf_replace_node = NULL;
2859 g_conf_replace_offset = 0;
2860
2861 if (g_img_chunk_list.chunk)
2862 {
2863 grub_free(g_img_chunk_list.chunk);
2864 }
2865
2866 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2867 {
2868 grub_file_close(file);
2869 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2870 }
2871
2872 /* get image chunk data */
2873 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2874 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2875 if (NULL == g_img_chunk_list.chunk)
2876 {
2877 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2878 }
2879
2880 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2881 g_img_chunk_list.cur_chunk = 0;
2882
2883 start = file->device->disk->partition->start;
2884
2885 ventoy_get_block_list(file, &g_img_chunk_list, start);
2886
2887 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2888 grub_file_close(file);
2889
2890 if (rc)
2891 {
2892 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2893 }
2894
2895 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2896 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2897 }
2898
2899 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2900 {
2901 grub_uint64_t offset = 0;
2902 grub_uint32_t align = 0;
2903 grub_file_t file = NULL;
2904 conf_replace *node = NULL;
2905
2906 (void)ctxt;
2907 (void)argc;
2908 (void)args;
2909
2910 debug("select conf replace argc:%d\n", argc);
2911
2912 if (argc < 2)
2913 {
2914 return 0;
2915 }
2916
2917 node = ventoy_plugin_find_conf_replace(args[1]);
2918 if (!node)
2919 {
2920 debug("Conf replace not found for %s\n", args[1]);
2921 goto end;
2922 }
2923
2924 debug("Find conf replace for %s\n", args[1]);
2925
2926 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2927 if (!file)
2928 {
2929 debug("<(loop)%s> NOT exist\n", node->orgconf);
2930 goto end;
2931 }
2932
2933 offset = grub_iso9660_get_last_file_dirent_pos(file);
2934 grub_file_close(file);
2935
2936 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2937 if (!file)
2938 {
2939 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2940 goto end;
2941 }
2942
2943 align = ((int)file->size + 2047) / 2048 * 2048;
2944
2945 if (align > vtoy_max_replace_file_size)
2946 {
2947 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2948 goto end;
2949 }
2950
2951 grub_file_read(file, g_conf_replace_new_buf, file->size);
2952 g_conf_replace_new_len = (int)file->size;
2953 g_conf_replace_new_len_align = align;
2954
2955 g_conf_replace_node = node;
2956 g_conf_replace_offset = offset + 2;
2957
2958 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2959
2960 end:
2961 if (file)
2962 {
2963 grub_file_close(file);
2964 }
2965 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2966 }
2967
2968 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2969 {
2970 int i = 0;
2971 int pos = 0;
2972 char *buf = NULL;
2973 char configfile[128];
2974 install_template *node = NULL;
2975
2976 (void)ctxt;
2977 (void)argc;
2978 (void)args;
2979
2980 debug("select auto installation argc:%d\n", argc);
2981
2982 if (argc < 1)
2983 {
2984 return 0;
2985 }
2986
2987 node = ventoy_plugin_find_install_template(args[0]);
2988 if (!node)
2989 {
2990 debug("Auto install template not found for %s\n", args[0]);
2991 return 0;
2992 }
2993
2994 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2995 {
2996 node->cursel = node->autosel - 1;
2997 debug("Auto install template auto select %d\n", node->autosel);
2998 return 0;
2999 }
3000
3001 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3002 if (!buf)
3003 {
3004 return 0;
3005 }
3006
3007 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3008 " echo %s\n}\n", "123");
3009
3010 for (i = 0; i < node->templatenum; i++)
3011 {
3012 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3013 " echo 123\n}\n",
3014 node->templatepath[i].path);
3015 }
3016
3017 g_ventoy_menu_esc = 1;
3018 g_ventoy_suppress_esc = 1;
3019
3020 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3021 grub_script_execute_sourcecode(configfile);
3022
3023 g_ventoy_menu_esc = 0;
3024 g_ventoy_suppress_esc = 0;
3025
3026 grub_free(buf);
3027
3028 node->cursel = g_ventoy_last_entry - 1;
3029
3030 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3031 }
3032
3033 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3034 {
3035 int i = 0;
3036 int pos = 0;
3037 char *buf = NULL;
3038 char configfile[128];
3039 persistence_config *node;
3040
3041 (void)ctxt;
3042 (void)argc;
3043 (void)args;
3044
3045 debug("select persistence argc:%d\n", argc);
3046
3047 if (argc < 1)
3048 {
3049 return 0;
3050 }
3051
3052 node = ventoy_plugin_find_persistent(args[0]);
3053 if (!node)
3054 {
3055 debug("Persistence image not found for %s\n", args[0]);
3056 return 0;
3057 }
3058
3059 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3060 {
3061 node->cursel = node->autosel - 1;
3062 debug("Persistence image auto select %d\n", node->autosel);
3063 return 0;
3064 }
3065
3066 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3067 if (!buf)
3068 {
3069 return 0;
3070 }
3071
3072 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3073 " echo %s\n}\n", "123");
3074
3075 for (i = 0; i < node->backendnum; i++)
3076 {
3077 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3078 " echo 123\n}\n",
3079 node->backendpath[i].path);
3080
3081 }
3082
3083 g_ventoy_menu_esc = 1;
3084 g_ventoy_suppress_esc = 1;
3085
3086 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3087 grub_script_execute_sourcecode(configfile);
3088
3089 g_ventoy_menu_esc = 0;
3090 g_ventoy_suppress_esc = 0;
3091
3092 grub_free(buf);
3093
3094 node->cursel = g_ventoy_last_entry - 1;
3095
3096 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3097 }
3098
3099 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3100 {
3101 grub_uint32_t i;
3102 ventoy_img_chunk *cur;
3103
3104 (void)ctxt;
3105 (void)argc;
3106 (void)args;
3107
3108 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3109 {
3110 cur = g_img_chunk_list.chunk + i;
3111 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3112 cur->img_start_sector, cur->img_end_sector,
3113 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3114 );
3115 }
3116
3117 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3118 }
3119
3120 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3121 {
3122 grub_uint32_t i;
3123 grub_file_t file;
3124 ventoy_img_chunk_list chunklist;
3125
3126 (void)ctxt;
3127 (void)argc;
3128
3129 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3130 if (!file)
3131 {
3132 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3133 }
3134
3135 /* get image chunk data */
3136 grub_memset(&chunklist, 0, sizeof(chunklist));
3137 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3138 if (NULL == chunklist.chunk)
3139 {
3140 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3141 }
3142
3143 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3144 chunklist.cur_chunk = 0;
3145
3146 ventoy_get_block_list(file, &chunklist, 0);
3147
3148 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3149 {
3150 grub_printf("########## UNSUPPORTED ###############\n");
3151 }
3152
3153 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3154
3155 for (i = 0; i < chunklist.cur_chunk; i++)
3156 {
3157 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3158 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3159 }
3160
3161 grub_printf("\n==================================\n");
3162
3163 for (i = 0; i < chunklist.cur_chunk; i++)
3164 {
3165 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3166 (ulonglong)chunklist.chunk[i].img_start_sector,
3167 (ulonglong)chunklist.chunk[i].img_end_sector,
3168 (ulonglong)chunklist.chunk[i].disk_start_sector,
3169 (ulonglong)chunklist.chunk[i].disk_end_sector
3170 );
3171 }
3172
3173 grub_free(chunklist.chunk);
3174 grub_file_close(file);
3175
3176 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3177 }
3178
3179 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3180 {
3181 int i;
3182 ventoy_grub_param_file_replace *replace = NULL;
3183
3184 (void)ctxt;
3185 (void)argc;
3186 (void)args;
3187
3188 if (argc >= 2)
3189 {
3190 replace = &(g_grub_param->file_replace);
3191 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3192
3193 replace->old_name_cnt = 0;
3194 for (i = 0; i < 4 && i + 1 < argc; i++)
3195 {
3196 replace->old_name_cnt++;
3197 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3198 }
3199
3200 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3201 }
3202
3203 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3204 }
3205
3206 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3207 {
3208 char buf[32];
3209 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3210
3211 (void)ctxt;
3212
3213 if (argc >= 1)
3214 {
3215 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3216 grub_env_set(args[0], buf);
3217 }
3218
3219 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3220 }
3221
3222 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3223 {
3224 (void)ctxt;
3225 (void)argc;
3226 (void)args;
3227
3228 if (argc == 0)
3229 {
3230 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3231 grub_printf("%s", g_list_script_buf);
3232 }
3233 else
3234 {
3235 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3236 grub_printf("%s", g_tree_script_buf);
3237 }
3238
3239 return 0;
3240 }
3241
3242 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3243 {
3244 img_info *cur = g_ventoy_img_list;
3245
3246 (void)ctxt;
3247 (void)argc;
3248 (void)args;
3249
3250 while (cur)
3251 {
3252 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3253 grub_printf("name:<%s>\n\n", cur->name);
3254 cur = cur->next;
3255 }
3256
3257 return 0;
3258 }
3259
3260 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3261 {
3262 (void)ctxt;
3263 (void)argc;
3264 (void)args;
3265
3266 ventoy_plugin_dump_injection();
3267
3268 return 0;
3269 }
3270
3271 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3272 {
3273 (void)ctxt;
3274 (void)argc;
3275 (void)args;
3276
3277 ventoy_plugin_dump_auto_install();
3278
3279 return 0;
3280 }
3281
3282 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3283 {
3284 (void)ctxt;
3285 (void)argc;
3286 (void)args;
3287
3288 ventoy_plugin_dump_persistence();
3289
3290 return 0;
3291 }
3292
3293 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3294 {
3295 (void)ctxt;
3296 (void)argc;
3297 (void)args;
3298
3299 if (argc != 1)
3300 {
3301 return 1;
3302 }
3303
3304 if (args[0][0] == '0')
3305 {
3306 return g_ventoy_memdisk_mode ? 0 : 1;
3307 }
3308 else if (args[0][0] == '1')
3309 {
3310 return g_ventoy_iso_raw ? 0 : 1;
3311 }
3312 else if (args[0][0] == '2')
3313 {
3314 return g_ventoy_iso_uefi_drv ? 0 : 1;
3315 }
3316 else if (args[0][0] == '3')
3317 {
3318 return g_ventoy_grub2_mode ? 0 : 1;
3319 }
3320 else if (args[0][0] == '4')
3321 {
3322 return g_ventoy_wimboot_mode ? 0 : 1;
3323 }
3324
3325 return 1;
3326 }
3327
3328 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3329 {
3330 static int configfile_mode = 0;
3331 char memfile[128] = {0};
3332
3333 (void)ctxt;
3334 (void)argc;
3335 (void)args;
3336
3337 /*
3338 * args[0]: 0:normal 1:configfile
3339 * args[1]: 0:list_buf 1:tree_buf
3340 */
3341
3342 if (argc != 2)
3343 {
3344 debug("Invalid argc %d\n", argc);
3345 return 0;
3346 }
3347
3348 VTOY_CMD_CHECK(1);
3349
3350 if (args[0][0] == '0')
3351 {
3352 if (args[1][0] == '0')
3353 {
3354 grub_script_execute_sourcecode(g_list_script_buf);
3355 }
3356 else
3357 {
3358 grub_script_execute_sourcecode(g_tree_script_buf);
3359 }
3360 }
3361 else
3362 {
3363 if (configfile_mode)
3364 {
3365 debug("Now already in F3 mode %d\n", configfile_mode);
3366 return 0;
3367 }
3368
3369 if (args[1][0] == '0')
3370 {
3371 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3372 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3373 }
3374 else
3375 {
3376 g_ventoy_last_entry = -1;
3377 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3378 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3379 }
3380
3381 configfile_mode = 1;
3382 grub_script_execute_sourcecode(memfile);
3383 configfile_mode = 0;
3384 }
3385
3386 return 0;
3387 }
3388
3389 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3390 {
3391 grub_file_t file;
3392
3393 (void)ctxt;
3394
3395 if (argc != 1)
3396 {
3397 return 1;
3398 }
3399
3400 g_ventoy_case_insensitive = 1;
3401 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3402 g_ventoy_case_insensitive = 0;
3403
3404 grub_errno = 0;
3405
3406 if (file)
3407 {
3408 grub_file_close(file);
3409 return 0;
3410 }
3411 return 1;
3412 }
3413
3414 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3415 {
3416 int id = 0;
3417 int find = 0;
3418 grub_disk_t disk;
3419 const char *isopath = NULL;
3420 char hdname[32];
3421 ventoy_mbr_head mbr;
3422
3423 (void)ctxt;
3424 (void)argc;
3425
3426 if (argc != 1)
3427 {
3428 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3429 }
3430
3431 isopath = grub_env_get("vtoy_iso_part");
3432 if (!isopath)
3433 {
3434 debug("isopath is null %p\n", isopath);
3435 return 0;
3436 }
3437
3438 debug("isopath is %s\n", isopath);
3439
3440 for (id = 0; id < 30 && (find == 0); id++)
3441 {
3442 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3443 if (grub_strstr(isopath, hdname))
3444 {
3445 debug("skip %s ...\n", hdname);
3446 continue;
3447 }
3448
3449 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3450
3451 disk = grub_disk_open(hdname);
3452 if (!disk)
3453 {
3454 debug("%s not exist\n", hdname);
3455 break;
3456 }
3457
3458 grub_memset(&mbr, 0, sizeof(mbr));
3459 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3460 {
3461 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3462 {
3463 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3464 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3465 {
3466
3467 grub_env_set(args[0], hdname);
3468 find = 1;
3469 }
3470 }
3471 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3472 }
3473 else
3474 {
3475 debug("read %s failed\n", hdname);
3476 }
3477
3478 grub_disk_close(disk);
3479 }
3480
3481 return 0;
3482 }
3483
3484 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3485 {
3486 int len = 1024;
3487 grub_file_t file;
3488 char *buf = NULL;
3489
3490 (void)ctxt;
3491 (void)argc;
3492
3493 if (argc != 2)
3494 {
3495 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3496 }
3497
3498 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3499 if (!file)
3500 {
3501 debug("failed to open file %s\n", args[0]);
3502 return 0;
3503 }
3504
3505 buf = grub_malloc(len);
3506 if (!buf)
3507 {
3508 goto end;
3509 }
3510
3511 buf[len - 1] = 0;
3512 grub_file_read(file, buf, len - 1);
3513
3514 ventoy_get_line(buf);
3515 ventoy_set_env(args[1], buf);
3516
3517 end:
3518
3519 grub_check_free(buf);
3520 grub_file_close(file);
3521
3522 return 0;
3523 }
3524
3525 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3526 {
3527 int *pCnt = (int *)data;
3528
3529 (void)disk;
3530
3531 (*pCnt)++;
3532 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3533 "0 %llu linear /dev/ventoy %llu\n",
3534 (ulonglong)partition->len, (ulonglong)partition->start);
3535
3536 return 0;
3537 }
3538
3539 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3540 {
3541 int cnt = 0;
3542 char *device_name = NULL;
3543 grub_device_t dev = NULL;
3544 char buf[64];
3545
3546 (void)ctxt;
3547
3548 g_part_list_pos = 0;
3549 grub_env_unset("vtoy_img_part_file");
3550
3551 if (argc != 1)
3552 {
3553 return 1;
3554 }
3555
3556 device_name = grub_file_get_device_name(args[0]);
3557 if (!device_name)
3558 {
3559 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3560 goto end;
3561 }
3562
3563 dev = grub_device_open(device_name);
3564 if (!dev)
3565 {
3566 debug("grub_device_open failed, %s\n", device_name);
3567 goto end;
3568 }
3569
3570 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
3571
3572 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3573 grub_env_set("vtoy_img_part_file", buf);
3574
3575 grub_snprintf(buf, sizeof(buf), "%d", cnt);
3576 grub_env_set("vtoy_img_part_cnt", buf);
3577
3578 end:
3579
3580 check_free(device_name, grub_free);
3581 check_free(dev, grub_device_close);
3582
3583 return 0;
3584 }
3585
3586
3587 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3588 {
3589 int rc = 1;
3590 grub_file_t file;
3591 char *buf = NULL;
3592
3593 (void)ctxt;
3594 (void)argc;
3595
3596 if (argc != 2)
3597 {
3598 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3599 }
3600
3601 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3602 if (!file)
3603 {
3604 debug("failed to open file %s\n", args[0]);
3605 return 1;
3606 }
3607
3608 buf = grub_malloc(file->size + 1);
3609 if (!buf)
3610 {
3611 goto end;
3612 }
3613
3614 buf[file->size] = 0;
3615 grub_file_read(file, buf, file->size);
3616
3617 if (grub_strstr(buf, args[1]))
3618 {
3619 rc = 0;
3620 }
3621
3622 end:
3623
3624 grub_check_free(buf);
3625 grub_file_close(file);
3626
3627 return rc;
3628 }
3629
3630 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3631 {
3632 int len;
3633 grub_file_t file;
3634 char buf[64];
3635 grub_uint64_t size;
3636 ventoy_iso9660_vd pvd;
3637
3638 (void)ctxt;
3639 (void)argc;
3640
3641 if (argc != 4)
3642 {
3643 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3644 }
3645
3646 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3647 if (!file)
3648 {
3649 debug("failed to open file %s\n", args[0]);
3650 return 0;
3651 }
3652
3653 grub_file_seek(file, 16 * 2048);
3654 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3655 if (len != sizeof(pvd))
3656 {
3657 debug("failed to read pvd %d\n", len);
3658 goto end;
3659 }
3660
3661 grub_memset(buf, 0, sizeof(buf));
3662 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3663 ventoy_set_env(args[1], buf);
3664
3665 grub_memset(buf, 0, sizeof(buf));
3666 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3667 ventoy_set_env(args[2], buf);
3668
3669 size = pvd.space;
3670 size *= 2048;
3671 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3672 ventoy_set_env(args[3], buf);
3673
3674 end:
3675 grub_file_close(file);
3676
3677 return 0;
3678 }
3679
3680 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3681 {
3682 int len;
3683 grub_file_t file;
3684 char buf[64];
3685
3686 (void)ctxt;
3687 (void)argc;
3688
3689 if (argc != 2)
3690 {
3691 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3692 }
3693
3694 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3695 if (!file)
3696 {
3697 debug("failed to open file %s\n", args[0]);
3698 return 0;
3699 }
3700
3701 grub_memset(buf, 0, sizeof(buf));
3702 grub_file_seek(file, 16 * 2048 + 813);
3703 len = (int)grub_file_read(file, buf, 17);
3704 if (len != 17)
3705 {
3706 debug("failed to read create date %d\n", len);
3707 goto end;
3708 }
3709
3710 ventoy_set_env(args[1], buf);
3711
3712 end:
3713 grub_file_close(file);
3714
3715 return 0;
3716 }
3717
3718 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3719 {
3720 (void)ctxt;
3721 (void)argc;
3722 (void)args;
3723
3724 ventoy_env_hook_root(1);
3725
3726 return 0;
3727 }
3728
3729 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3730 {
3731 (void)ctxt;
3732 (void)argc;
3733 (void)args;
3734
3735 ventoy_env_hook_root(0);
3736
3737 return 0;
3738 }
3739
3740 #ifdef GRUB_MACHINE_EFI
3741 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3742 {
3743 int ret = 1;
3744 grub_uint8_t *var;
3745 grub_size_t size;
3746 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3747
3748 (void)ctxt;
3749 (void)argc;
3750 (void)args;
3751
3752 var = grub_efi_get_variable("SecureBoot", &global, &size);
3753 if (var && *var == 1)
3754 {
3755 return 0;
3756 }
3757
3758 return ret;
3759 }
3760 #else
3761 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3762 {
3763 (void)ctxt;
3764 (void)argc;
3765 (void)args;
3766 return 1;
3767 }
3768 #endif
3769
3770 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3771 {
3772 int i;
3773 int ret = 1;
3774 grub_file_t file;
3775 grub_uint64_t FileSectors = 0;
3776 ventoy_gpt_info *gpt = NULL;
3777 ventoy_part_table *pt = NULL;
3778 grub_uint8_t zeroguid[16] = {0};
3779
3780 (void)ctxt;
3781 (void)argc;
3782
3783 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3784 if (!file)
3785 {
3786 debug("failed to open file %s\n", args[0]);
3787 return 1;
3788 }
3789
3790 if (file->size % 512)
3791 {
3792 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3793 goto out;
3794 }
3795
3796 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3797 if (!gpt)
3798 {
3799 goto out;
3800 }
3801
3802 FileSectors = file->size / 512;
3803
3804 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3805 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3806 {
3807 debug("This is EFI partition table\n");
3808
3809 for (i = 0; i < 128; i++)
3810 {
3811 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3812 {
3813 if (FileSectors < gpt->PartTbl[i].LastLBA)
3814 {
3815 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3816 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3817 goto out;
3818 }
3819 }
3820 }
3821 }
3822 else
3823 {
3824 debug("This is MBR partition table\n");
3825
3826 for (i = 0; i < 4; i++)
3827 {
3828 pt = gpt->MBR.PartTbl + i;
3829 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3830 {
3831 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3832 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3833 (ulonglong)FileSectors);
3834 goto out;
3835 }
3836 }
3837 }
3838
3839 ret = 0;
3840
3841 out:
3842 grub_file_close(file);
3843 grub_check_free(gpt);
3844 grub_errno = GRUB_ERR_NONE;
3845 return ret;
3846 }
3847
3848 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3849 {
3850 int i;
3851 int ret;
3852
3853 (void)ctxt;
3854 (void)argc;
3855 (void)args;
3856
3857 for (i = 0; i < 500; i++)
3858 {
3859 ret = grub_getkey_noblock();
3860 if (ret == GRUB_TERM_NO_KEY)
3861 {
3862 break;
3863 }
3864 }
3865
3866 if (i >= 500)
3867 {
3868 grub_cls();
3869 grub_printf("\n\n Still have key input after clear.\n");
3870 grub_refresh();
3871 grub_sleep(5);
3872 }
3873
3874 return 0;
3875 }
3876
3877 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3878 {
3879 int i;
3880 int buflen;
3881 int datalen;
3882 int loclen;
3883 int img_chunk_num;
3884 int image_sector_size;
3885 char cmd[64];
3886 ventoy_chain_head *chain;
3887 ventoy_img_chunk *chunk;
3888 ventoy_os_param *osparam;
3889 ventoy_image_location *location;
3890 ventoy_image_disk_region *region;
3891 struct grub_acpi_table_header *acpi;
3892
3893 (void)ctxt;
3894
3895 if (argc != 2)
3896 {
3897 return 1;
3898 }
3899
3900 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3901
3902 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3903 if (!chain)
3904 {
3905 return 1;
3906 }
3907
3908 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3909
3910 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3911 {
3912 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3913 return 1;
3914 }
3915
3916 img_chunk_num = chain->img_chunk_num;
3917
3918 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3919 datalen = sizeof(ventoy_os_param) + loclen;
3920
3921 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3922 acpi = grub_zalloc(buflen);
3923 if (!acpi)
3924 {
3925 return 1;
3926 }
3927
3928 /* Step1: Fill acpi table header */
3929 grub_memcpy(acpi->signature, "VTOY", 4);
3930 acpi->length = buflen;
3931 acpi->revision = 1;
3932 grub_memcpy(acpi->oemid, "VENTOY", 6);
3933 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3934 acpi->oemrev = 1;
3935 acpi->creator_id[0] = 1;
3936 acpi->creator_rev = 1;
3937
3938 /* Step2: Fill data */
3939 osparam = (ventoy_os_param *)(acpi + 1);
3940 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3941 osparam->vtoy_img_location_addr = 0;
3942 osparam->vtoy_img_location_len = loclen;
3943 osparam->chksum = 0;
3944 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3945
3946 location = (ventoy_image_location *)(osparam + 1);
3947 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3948 location->image_sector_size = image_sector_size;
3949 location->disk_sector_size = chain->disk_sector_size;
3950 location->region_count = img_chunk_num;
3951
3952 region = location->regions;
3953 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3954 if (512 == image_sector_size)
3955 {
3956 for (i = 0; i < img_chunk_num; i++)
3957 {
3958 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3959 region->image_start_sector = chunk->img_start_sector * 4;
3960 region->disk_start_sector = chunk->disk_start_sector;
3961 region++;
3962 chunk++;
3963 }
3964 }
3965 else
3966 {
3967 for (i = 0; i < img_chunk_num; i++)
3968 {
3969 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3970 region->image_start_sector = chunk->img_start_sector;
3971 region->disk_start_sector = chunk->disk_start_sector;
3972 region++;
3973 chunk++;
3974 }
3975 }
3976
3977 /* Step3: Fill acpi checksum */
3978 acpi->checksum = 0;
3979 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3980
3981 /* load acpi table */
3982 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3983 grub_script_execute_sourcecode(cmd);
3984
3985 grub_free(acpi);
3986
3987 VENTOY_CMD_RETURN(0);
3988 }
3989
3990 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3991 {
3992 (void)ctxt;
3993 (void)argc;
3994 (void)args;
3995
3996 g_ventoy_last_entry_back = g_ventoy_last_entry;
3997 g_ventoy_last_entry = -1;
3998
3999 return 0;
4000 }
4001
4002 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4003 {
4004 (void)ctxt;
4005 (void)argc;
4006 (void)args;
4007
4008 g_ventoy_last_entry = g_ventoy_last_entry_back;
4009
4010 return 0;
4011 }
4012
4013 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4014 {
4015 const char *pos = filename + 1;
4016
4017 if (info->dir)
4018 {
4019 while (*pos)
4020 {
4021 if (*pos == '.')
4022 {
4023 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4024 {
4025 grub_strncpy((char *)data, filename, 128);
4026 return 1;
4027 }
4028 }
4029 pos++;
4030 }
4031 }
4032
4033 return 0;
4034 }
4035
4036 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4037 {
4038 int rc = 1;
4039 char *device_name = NULL;
4040 grub_device_t dev = NULL;
4041 grub_fs_t fs = NULL;
4042 char buf[128] = {0};
4043
4044 (void)ctxt;
4045
4046 if (argc != 3)
4047 {
4048 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4049 return 1;
4050 }
4051
4052 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4053
4054 device_name = grub_file_get_device_name(args[0]);
4055 if (!device_name)
4056 {
4057 debug("grub_file_get_device_name failed, %s\n", args[0]);
4058 goto end;
4059 }
4060
4061 dev = grub_device_open(device_name);
4062 if (!dev)
4063 {
4064 debug("grub_device_open failed, %s\n", device_name);
4065 goto end;
4066 }
4067
4068 fs = grub_fs_probe(dev);
4069 if (!fs)
4070 {
4071 debug("grub_fs_probe failed, %s\n", device_name);
4072 goto end;
4073 }
4074
4075 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4076
4077 if (buf[0])
4078 {
4079 ventoy_set_env(args[2], buf);
4080 }
4081
4082 rc = 0;
4083
4084 end:
4085
4086 check_free(device_name, grub_free);
4087 check_free(dev, grub_device_close);
4088
4089 return rc;
4090 }
4091
4092 int ventoy_load_part_table(const char *diskname)
4093 {
4094 char name[64];
4095 int ret;
4096 grub_disk_t disk;
4097 grub_device_t dev;
4098
4099 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4100 if (!g_ventoy_part_info)
4101 {
4102 return 1;
4103 }
4104
4105 disk = grub_disk_open(diskname);
4106 if (!disk)
4107 {
4108 debug("Failed to open disk %s\n", diskname);
4109 return 1;
4110 }
4111
4112 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4113
4114 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4115 grub_disk_close(disk);
4116
4117 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4118 dev = grub_device_open(name);
4119 if (dev)
4120 {
4121 /* Check for official Ventoy device */
4122 ret = ventoy_check_official_device(dev);
4123 grub_device_close(dev);
4124
4125 if (ret)
4126 {
4127 return 1;
4128 }
4129 }
4130
4131 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4132 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4133
4134 return 0;
4135 }
4136
4137 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4138 {
4139 int ret;
4140
4141 (void)argc;
4142 (void)ctxt;
4143
4144 ret = ventoy_load_part_table(args[0]);
4145 if (ret)
4146 {
4147 grub_exit();
4148 }
4149
4150 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4151 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4152
4153 return 0;
4154 }
4155
4156 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4157 {
4158 int ret = 1;
4159 const char *vcfg = NULL;
4160
4161 (void)argc;
4162 (void)ctxt;
4163
4164 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4165 if (vcfg)
4166 {
4167 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4168 grub_env_set(args[1], vcfg);
4169 ret = 0;
4170 }
4171 else
4172 {
4173 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4174 }
4175
4176 grub_errno = 0;
4177 return ret;
4178 }
4179
4180
4181 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4182 {
4183 int id;
4184 grub_uint8_t zeroguid[16] = {0};
4185
4186 (void)argc;
4187 (void)ctxt;
4188
4189 id = (int)grub_strtoul(args[0], NULL, 10);
4190 grub_errno = 0;
4191
4192 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4193 {
4194 if (id >= 1 && id <= 128)
4195 {
4196 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4197 {
4198 return 0;
4199 }
4200 }
4201 }
4202 else
4203 {
4204 if (id >= 1 && id <= 4)
4205 {
4206 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4207 {
4208 return 0;
4209 }
4210 }
4211 }
4212
4213 return 1;
4214 }
4215
4216 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4217 {
4218 int rc = 1;
4219 char *device_name = NULL;
4220 grub_device_t dev = NULL;
4221 grub_fs_t fs = NULL;
4222 char *label = NULL;
4223
4224 (void)ctxt;
4225
4226 debug("get fs label for %s\n", args[0]);
4227
4228 if (argc != 2)
4229 {
4230 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4231 return 1;
4232 }
4233
4234 device_name = grub_file_get_device_name(args[0]);
4235 if (!device_name)
4236 {
4237 debug("grub_file_get_device_name failed, %s\n", args[0]);
4238 goto end;
4239 }
4240
4241 dev = grub_device_open(device_name);
4242 if (!dev)
4243 {
4244 debug("grub_device_open failed, %s\n", device_name);
4245 goto end;
4246 }
4247
4248 fs = grub_fs_probe(dev);
4249 if (NULL == fs || NULL == fs->fs_label)
4250 {
4251 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4252 goto end;
4253 }
4254
4255 fs->fs_label(dev, &label);
4256 if (label)
4257 {
4258 debug("label=<%s>\n", label);
4259 ventoy_set_env(args[1], label);
4260 grub_free(label);
4261 }
4262
4263 rc = 0;
4264
4265 end:
4266
4267 check_free(device_name, grub_free);
4268 check_free(dev, grub_device_close);
4269
4270 return rc;
4271 }
4272
4273 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4274 {
4275 if (!info->dir)
4276 {
4277 grub_snprintf((char *)data, 256, "%s", filename);
4278 return 1;
4279 }
4280
4281 return 0;
4282 }
4283
4284 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4285 {
4286 if (info->dir && filename && filename[0] != '.')
4287 {
4288 grub_snprintf((char *)data, 256, "%s", filename);
4289 return 1;
4290 }
4291
4292 return 0;
4293 }
4294
4295 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4296 {
4297 int rc = 1;
4298 char *device_name = NULL;
4299 grub_device_t dev = NULL;
4300 grub_fs_t fs = NULL;
4301 char name[256] ={0};
4302
4303 if (argc != 3)
4304 {
4305 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4306 return 1;
4307 }
4308
4309 device_name = grub_file_get_device_name(args[0]);
4310 if (!device_name)
4311 {
4312 debug("grub_file_get_device_name failed, %s\n", args[0]);
4313 goto end;
4314 }
4315
4316 dev = grub_device_open(device_name);
4317 if (!dev)
4318 {
4319 debug("grub_device_open failed, %s\n", device_name);
4320 goto end;
4321 }
4322
4323 fs = grub_fs_probe(dev);
4324 if (!fs)
4325 {
4326 debug("grub_fs_probe failed, %s\n", device_name);
4327 goto end;
4328 }
4329
4330 fs->fs_dir(dev, args[1], hook, name);
4331 if (name[0])
4332 {
4333 ventoy_set_env(args[2], name);
4334 }
4335
4336 rc = 0;
4337
4338 end:
4339
4340 check_free(device_name, grub_free);
4341 check_free(dev, grub_device_close);
4342
4343 return rc;
4344 }
4345
4346 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4347 {
4348 (void)ctxt;
4349 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4350 }
4351
4352 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4353 {
4354 (void)ctxt;
4355 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4356 }
4357
4358 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4359 {
4360 char c;
4361 char *pos = NULL;
4362 char *end = NULL;
4363
4364 (void)ctxt;
4365
4366 if (argc != 2)
4367 {
4368 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4369 return 1;
4370 }
4371
4372 for (pos = args[0]; *pos; pos++)
4373 {
4374 if (*pos == '.')
4375 {
4376 end = pos;
4377 }
4378 }
4379
4380 if (end)
4381 {
4382 c = *end;
4383 *end = 0;
4384 }
4385
4386 grub_env_set(args[1], args[0]);
4387
4388 if (end)
4389 {
4390 *end = c;
4391 }
4392
4393 return 0;
4394 }
4395
4396 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4397 {
4398 int i;
4399 int len;
4400 const char *buf;
4401
4402 (void)ctxt;
4403
4404 if (argc != 2)
4405 {
4406 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4407 return 1;
4408 }
4409
4410 buf = args[0];
4411 len = (int)grub_strlen(buf);
4412 for (i = len; i > 0; i--)
4413 {
4414 if (buf[i - 1] == '/')
4415 {
4416 grub_env_set(args[1], buf + i);
4417 return 0;
4418 }
4419 }
4420
4421 grub_env_set(args[1], buf);
4422
4423 return 0;
4424 }
4425
4426 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4427 {
4428 struct grub_video_mode_info info;
4429 char buf[32];
4430
4431 (void)ctxt;
4432 (void)argc;
4433 (void)args;
4434
4435 if (!g_video_mode_list)
4436 {
4437 ventoy_enum_video_mode();
4438 }
4439
4440 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4441 {
4442 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4443 }
4444 else
4445 {
4446 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4447 }
4448
4449 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4450
4451 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4452 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4453
4454 VENTOY_CMD_RETURN(0);
4455 }
4456
4457 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4458 {
4459 struct grub_video_mode_info info;
4460 char buf[32];
4461
4462 (void)ctxt;
4463 (void)argc;
4464 (void)args;
4465
4466 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4467 {
4468 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4469 }
4470 else
4471 {
4472 grub_snprintf(buf, sizeof(buf), "0x0x0");
4473 }
4474
4475 grub_env_set(args[0], buf);
4476
4477 VENTOY_CMD_RETURN(0);
4478 }
4479
4480 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4481 {
4482 int id;
4483 char buf[32];
4484
4485 (void)ctxt;
4486 (void)argc;
4487
4488 if (!g_video_mode_list)
4489 {
4490 return 0;
4491 }
4492
4493 id = (int)grub_strtoul(args[0], NULL, 10);
4494 if (id < g_video_mode_num)
4495 {
4496 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4497 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4498 }
4499
4500 grub_env_set(args[1], buf);
4501
4502 VENTOY_CMD_RETURN(0);
4503 }
4504
4505 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4506 {
4507 grub_uint32_t i;
4508 grub_uint32_t loadsector = 0;
4509 grub_file_t file;
4510 char value[32];
4511 grub_uint32_t boot_catlog = 0;
4512 grub_uint8_t buf[512];
4513
4514 (void)ctxt;
4515
4516 if (argc != 2)
4517 {
4518 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4519 return 1;
4520 }
4521
4522 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4523 if (!file)
4524 {
4525 debug("failed to open %s\n", args[0]);
4526 return 1;
4527 }
4528
4529 boot_catlog = ventoy_get_iso_boot_catlog(file);
4530 if (boot_catlog == 0)
4531 {
4532 debug("No bootcatlog found\n");
4533 grub_file_close(file);
4534 return 1;
4535 }
4536
4537 grub_memset(buf, 0, sizeof(buf));
4538 grub_file_seek(file, boot_catlog * 2048);
4539 grub_file_read(file, buf, sizeof(buf));
4540 grub_file_close(file);
4541
4542 for (i = 0; i < sizeof(buf); i += 32)
4543 {
4544 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4545 {
4546 if (buf[i + 32] == 0x88)
4547 {
4548 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4549 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4550 break;
4551 }
4552 }
4553 }
4554
4555 if (loadsector == 0)
4556 {
4557 debug("No EFI eltorito info found\n");
4558 return 1;
4559 }
4560
4561 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4562 grub_env_set(args[1], value);
4563 VENTOY_CMD_RETURN(0);
4564 }
4565
4566 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4567 {
4568 int curpos;
4569 int printlen;
4570 grub_size_t len;
4571 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4572
4573 if (pfsdir->initrd[0])
4574 {
4575 return 1;
4576 }
4577
4578 curpos = pfsdir->curpos;
4579 len = grub_strlen(filename);
4580
4581 if (info->dir)
4582 {
4583 if ((len == 1 && filename[0] == '.') ||
4584 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4585 {
4586 return 0;
4587 }
4588
4589 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4590 pfsdir->dircnt++;
4591
4592 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4593 pfsdir->curpos = curpos + printlen;
4594 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4595 pfsdir->curpos = curpos;
4596 pfsdir->fullpath[curpos] = 0;
4597 }
4598 else
4599 {
4600 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4601 pfsdir->filecnt++;
4602
4603 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4604 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4605 {
4606 if (info->size > 32 * VTOY_SIZE_1MB)
4607 {
4608 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4609 return 1;
4610 }
4611 }
4612 }
4613
4614 return 0;
4615 }
4616
4617 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4618 {
4619 int i;
4620 char *pos = NULL;
4621 char *device_name = NULL;
4622 grub_device_t dev = NULL;
4623 grub_fs_t fs = NULL;
4624 replace_fs_dir *pfsdir = NULL;
4625
4626 (void)ctxt;
4627
4628 if (argc != 2)
4629 {
4630 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4631 return 1;
4632 }
4633
4634 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4635 if (!pfsdir)
4636 {
4637 return 1;
4638 }
4639
4640 device_name = grub_file_get_device_name(args[0]);
4641 if (!device_name)
4642 {
4643 goto fail;
4644 }
4645
4646 dev = grub_device_open(device_name);
4647 if (!dev)
4648 {
4649 goto fail;
4650 }
4651
4652 fs = grub_fs_probe(dev);
4653 if (!fs)
4654 {
4655 goto fail;
4656 }
4657
4658 pfsdir->dev = dev;
4659 pfsdir->fs = fs;
4660 pfsdir->curpos = 1;
4661 pfsdir->fullpath[0] = '/';
4662 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4663
4664 if (pfsdir->initrd[0])
4665 {
4666 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4667
4668 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4669 {
4670 if (pfsdir->initrd[i] == '/')
4671 {
4672 pfsdir->initrd[i] = '\\';
4673 }
4674 }
4675
4676 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4677 grub_env_set(args[1], pos);
4678 }
4679 else
4680 {
4681 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4682 }
4683
4684 fail:
4685
4686 grub_check_free(pfsdir);
4687 grub_check_free(device_name);
4688 check_free(dev, grub_device_close);
4689
4690 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4691 }
4692
4693 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4694 {
4695 const char *pager = NULL;
4696
4697 (void)ctxt;
4698 (void)argc;
4699 (void)args;
4700
4701 pager = grub_env_get("pager");
4702 if (NULL == pager)
4703 {
4704 g_pager_flag = 1;
4705 grub_env_set("pager", "1");
4706 }
4707 else if (pager[0] == '1')
4708 {
4709 g_pager_flag = 0;
4710 }
4711 else
4712 {
4713 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
4714 g_pager_flag = 2;
4715 grub_env_set("pager", "1");
4716 }
4717
4718 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4719 }
4720
4721 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4722 {
4723 (void)ctxt;
4724 (void)argc;
4725 (void)args;
4726
4727 if (g_pager_flag == 1)
4728 {
4729 grub_env_unset("pager");
4730 }
4731 else if (g_pager_flag == 2)
4732 {
4733 grub_env_set("pager", g_old_pager);
4734 }
4735
4736 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4737 }
4738
4739 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4740 {
4741 if (g_json_case_mis_path[0])
4742 {
4743 return 1;
4744 }
4745
4746 if (0 == info->dir && grub_strncasecmp(filename, "ventoy.json", 11) == 0)
4747 {
4748 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
4749 return 1;
4750 }
4751 return 0;
4752 }
4753
4754 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4755 {
4756 char path[16];
4757 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
4758
4759 if (g_json_case_mis_path[0])
4760 {
4761 return 1;
4762 }
4763
4764 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
4765 {
4766 if (grub_strncasecmp(filename, "ventoy", 6) == 0)
4767 {
4768 grub_snprintf(path, sizeof(path), "/%s", filename);
4769 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
4770 if (g_json_case_mis_path[0])
4771 {
4772 return 1;
4773 }
4774 }
4775 }
4776
4777 return 0;
4778 }
4779
4780 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
4781 {
4782 int fstype = 0;
4783 char *device_name = NULL;
4784 grub_device_t dev = NULL;
4785 grub_fs_t fs = NULL;
4786 chk_case_fs_dir fs_dir;
4787
4788 (void)ctxt;
4789 (void)argc;
4790 (void)args;
4791
4792 device_name = grub_file_get_device_name(args[0]);
4793 if (!device_name)
4794 {
4795 goto out;
4796 }
4797
4798 dev = grub_device_open(device_name);
4799 if (!dev)
4800 {
4801 goto out;
4802 }
4803
4804 fs = grub_fs_probe(dev);
4805 if (!fs)
4806 {
4807 goto out;
4808 }
4809
4810 fstype = ventoy_get_fs_type(fs->name);
4811 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
4812 {
4813 goto out;
4814 }
4815
4816 g_json_case_mis_path[0] = 0;
4817 fs_dir.dev = dev;
4818 fs_dir.fs = fs;
4819 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
4820
4821 if (g_json_case_mis_path[0])
4822 {
4823 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
4824 }
4825
4826 out:
4827
4828 grub_check_free(device_name);
4829 check_free(dev, grub_device_close);
4830
4831 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4832 }
4833
4834 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
4835 {
4836 grub_disk_t disk;
4837 grub_partition_t part;
4838 char priority_str[3]; /* Maximum value 15 */
4839
4840 (void)ctxt;
4841
4842 if (argc < 2 || argc > 3)
4843 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4844 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
4845
4846 /* Open the disk if it exists */
4847 disk = grub_disk_open (args[0]);
4848 if (!disk)
4849 {
4850 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4851 "Not a disk");
4852 }
4853
4854 part = grub_partition_probe (disk, args[1]);
4855 if (!part)
4856 {
4857 grub_disk_close (disk);
4858 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4859 "No such partition");
4860 }
4861
4862 if (grub_strcmp (part->partmap->name, "gpt"))
4863 {
4864 grub_disk_close (disk);
4865 return grub_error (GRUB_ERR_BAD_PART_TABLE,
4866 "Not a GPT partition");
4867 }
4868
4869 grub_snprintf (priority_str, sizeof(priority_str), "%u",
4870 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
4871
4872 if (argc == 3)
4873 {
4874 grub_env_set (args[2], priority_str);
4875 grub_env_export (args[2]);
4876 }
4877 else
4878 {
4879 grub_printf ("Priority is %s\n", priority_str);
4880 }
4881
4882 grub_disk_close (disk);
4883 return GRUB_ERR_NONE;
4884 }
4885
4886
4887
4888 /* <BEGIN>: Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4889 #if 0
4890 void ventoy_tip_set_menu_label(const char *vid)
4891 {
4892 img_info *node;
4893
4894 g_ventoy_tip_msg1 = g_ventoy_tip_msg2 = NULL;
4895 if (vid)
4896 {
4897 node = (img_info *)(void *)grub_strtoul(vid + 4, NULL, 16);
4898 if (node)
4899 {
4900 g_ventoy_tip_msg1 = node->tip1;
4901 g_ventoy_tip_msg2 = node->tip2;
4902 }
4903 }
4904 }
4905 #endif /* #if 0 */
4906 /* <END> : Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4907
4908 int ventoy_env_init(void)
4909 {
4910 char buf[64];
4911
4912 grub_env_set("vtdebug_flag", "");
4913
4914 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4915 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4916 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4917 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4918
4919 ventoy_filt_register(0, ventoy_wrapper_open);
4920
4921 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4922 if (g_grub_param)
4923 {
4924 g_grub_param->grub_env_get = grub_env_get;
4925 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4926 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4927 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4928 grub_env_set("env_param", buf);
4929 grub_env_set("ventoy_env_param", buf);
4930
4931 grub_env_export("env_param");
4932 grub_env_export("ventoy_env_param");
4933 }
4934
4935 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
4936 grub_env_set("vtoy_winpeshl_ini_addr", buf);
4937
4938 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
4939 grub_env_set("vtoy_winpeshl_ini_size", buf);
4940
4941 grub_env_export("vtoy_winpeshl_ini_addr");
4942 grub_env_export("vtoy_winpeshl_ini_size");
4943
4944 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
4945 grub_env_set("vtoy_chain_file_size", buf);
4946 grub_env_export("vtoy_chain_file_size");
4947
4948 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
4949 grub_env_set("vtoy_chain_file_read", buf);
4950 grub_env_export("vtoy_chain_file_read");
4951
4952 return 0;
4953 }
4954
4955
4956
4957 static cmd_para ventoy_cmds[] =
4958 {
4959 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4960 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4961 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4962 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4963 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4964 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4965 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4966 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4967 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4968 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4969 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4970 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4971 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4972 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4973 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
4974 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4975 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4976 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4977 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4978 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4979 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4980 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4981 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4982 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4983
4984 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4985 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4986 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4987 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4988 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4989 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4990 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4991
4992 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4993 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4994 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4995 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4996 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
4997 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4998 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4999 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
5000 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
5001 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
5002
5003
5004 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
5005 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
5006 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
5007 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
5008 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
5009 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
5010 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
5011 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
5012 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
5013 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
5014 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
5015
5016 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
5017 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
5018 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
5019 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
5020 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
5021 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
5022 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
5023
5024 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5025 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5026 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
5027 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
5028 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
5029 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
5030 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
5031 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
5032 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
5033 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
5034
5035 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
5036 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
5037 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
5038 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
5039 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
5040 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
5041 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
5042 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
5043 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
5044
5045 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
5046 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
5047 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
5048 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
5049
5050
5051 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
5052 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
5053 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
5054
5055 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
5056 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
5057 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
5058
5059
5060 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
5061 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
5062 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
5063 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
5064 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
5065 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
5066 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
5067 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
5068 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
5069 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
5070 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
5071
5072 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
5073 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
5074 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
5075 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
5076 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
5077 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
5078 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
5079 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
5080 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
5081 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
5082
5083 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
5084 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
5085 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
5086 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
5087 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
5088 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
5089 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
5090 };
5091
5092 int ventoy_register_all_cmd(void)
5093 {
5094 grub_uint32_t i;
5095 cmd_para *cur = NULL;
5096
5097 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5098 {
5099 cur = ventoy_cmds + i;
5100 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
5101 cur->summary, cur->description, cur->parser);
5102 }
5103
5104 return 0;
5105 }
5106
5107 int ventoy_unregister_all_cmd(void)
5108 {
5109 grub_uint32_t i;
5110
5111 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5112 {
5113 grub_unregister_extcmd(ventoy_cmds[i].cmd);
5114 }
5115
5116 return 0;
5117 }
5118
5119