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