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