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