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