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