]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
facd0ede77c6104a95d92c6d0ef346cc0b3b5040
[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 char *last = NULL;
2616 const char *id = NULL;
2617 img_info *cur = NULL;
2618
2619 (void)ctxt;
2620
2621 if (argc < 1 || argc > 3)
2622 {
2623 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2624 }
2625
2626 if (g_fake_vlnk_src[0] && g_fake_vlnk_dst[0])
2627 {
2628 pos = grub_strchr(g_fake_vlnk_src, '/');
2629 grub_env_set(args[0], pos);
2630 if (argc > 1)
2631 {
2632 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(g_fake_vlnk_size));
2633 grub_env_set(args[1], value);
2634 }
2635
2636 if (argc > 2)
2637 {
2638 for (last = pos; *pos; pos++)
2639 {
2640 if (*pos == '/')
2641 {
2642 last = pos;
2643 }
2644 }
2645 grub_env_set(args[2], last + 1);
2646 }
2647
2648 goto end;
2649 }
2650
2651 id = grub_env_get("chosen");
2652
2653 pos = grub_strstr(id, "VID_");
2654 if (pos)
2655 {
2656 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2657 }
2658 else
2659 {
2660 cur = g_ventoy_img_list;
2661 }
2662
2663 if (!cur)
2664 {
2665 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2666 }
2667
2668 grub_env_set(args[0], cur->path);
2669
2670 if (argc > 1)
2671 {
2672 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2673 grub_env_set(args[1], value);
2674 }
2675
2676 if (argc > 2)
2677 {
2678 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2679 grub_env_set(args[2], cur->name);
2680 }
2681
2682 end:
2683 g_svd_replace_offset = 0;
2684
2685 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2686 }
2687
2688
2689 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2690 {
2691 int len;
2692 grub_fs_t fs;
2693 grub_device_t dev = NULL;
2694 img_info *cur = NULL;
2695 img_info *tail = NULL;
2696 img_info *min = NULL;
2697 img_info *head = NULL;
2698 const char *strdata = NULL;
2699 char *device_name = NULL;
2700 char buf[32];
2701 img_iterator_node *node = NULL;
2702 img_iterator_node *tmp = NULL;
2703
2704 (void)ctxt;
2705
2706 if (argc != 2)
2707 {
2708 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2709 }
2710
2711 if (g_ventoy_img_list || g_ventoy_img_count)
2712 {
2713 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2714 }
2715
2716 VTOY_CMD_CHECK(1);
2717
2718 g_enumerate_time_checked = 0;
2719 g_enumerate_start_time_ms = grub_get_time_ms();
2720
2721 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2722 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2723 {
2724 g_filt_dot_underscore_file = 1;
2725 }
2726
2727 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2728 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2729 {
2730 g_sort_case_sensitive = 1;
2731 }
2732
2733 device_name = grub_file_get_device_name(args[0]);
2734 if (!device_name)
2735 {
2736 goto fail;
2737 }
2738
2739 g_enum_dev = dev = grub_device_open(device_name);
2740 if (!dev)
2741 {
2742 goto fail;
2743 }
2744
2745 g_enum_fs = fs = grub_fs_probe(dev);
2746 if (!fs)
2747 {
2748 goto fail;
2749 }
2750
2751 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2752 {
2753 debug("unsupported fs:<%s>\n", fs->name);
2754 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2755 goto fail;
2756 }
2757
2758 ventoy_set_env("vtoy_iso_fs", fs->name);
2759
2760 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2761 if (strdata && strdata[0] == '1')
2762 {
2763 g_default_menu_mode = 1;
2764 }
2765
2766 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2767
2768 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2769
2770 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2771 if (strdata && strdata[0] == '/')
2772 {
2773 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2774 if (g_img_iterator_head.dir[len - 1] != '/')
2775 {
2776 g_img_iterator_head.dir[len++] = '/';
2777 }
2778 g_img_iterator_head.dirlen = len;
2779 }
2780 else
2781 {
2782 g_img_iterator_head.dirlen = 1;
2783 grub_strcpy(g_img_iterator_head.dir, "/");
2784 }
2785
2786 g_img_iterator_head.tail = &tail;
2787
2788 if (g_img_max_search_level < 0)
2789 {
2790 g_img_max_search_level = GRUB_INT_MAX;
2791 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2792 if (strdata && ventoy_is_decimal(strdata))
2793 {
2794 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2795 }
2796 }
2797
2798 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2799 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2800 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2801 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2802 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2803 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2804
2805 for (node = &g_img_iterator_head; node; node = node->next)
2806 {
2807 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2808 }
2809
2810 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2811 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2812 {
2813 g_tree_view_menu_style = 1;
2814 }
2815
2816 ventoy_set_default_menu();
2817
2818 for (node = &g_img_iterator_head; node; node = node->next)
2819 {
2820 ventoy_dynamic_tree_menu(node);
2821 }
2822
2823 /* free node */
2824 node = g_img_iterator_head.next;
2825 while (node)
2826 {
2827 tmp = node->next;
2828 grub_free(node);
2829 node = tmp;
2830 }
2831
2832 /* sort image list by image name */
2833 while (g_ventoy_img_list)
2834 {
2835 min = g_ventoy_img_list;
2836 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2837 {
2838 if (ventoy_cmp_img(min, cur) > 0)
2839 {
2840 min = cur;
2841 }
2842 }
2843
2844 if (min->prev)
2845 {
2846 min->prev->next = min->next;
2847 }
2848
2849 if (min->next)
2850 {
2851 min->next->prev = min->prev;
2852 }
2853
2854 if (min == g_ventoy_img_list)
2855 {
2856 g_ventoy_img_list = min->next;
2857 }
2858
2859 if (head == NULL)
2860 {
2861 head = tail = min;
2862 min->prev = NULL;
2863 min->next = NULL;
2864 }
2865 else
2866 {
2867 tail->next = min;
2868 min->prev = tail;
2869 min->next = NULL;
2870 tail = min;
2871 }
2872 }
2873
2874 g_ventoy_img_list = head;
2875
2876 if (g_default_menu_mode == 1)
2877 {
2878 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2879 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2880 " echo 'return ...' \n"
2881 "}\n", "<--");
2882 }
2883
2884 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2885 {
2886 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2887 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2888 " %s_%s \n"
2889 "}\n",
2890 cur->unsupport ? "[***********] " : "",
2891 cur->alias ? cur->alias : cur->name, cur->class, cur,
2892 cur->menu_prefix,
2893 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2894 }
2895
2896 g_tree_script_buf[g_tree_script_pos] = 0;
2897 g_list_script_buf[g_list_script_pos] = 0;
2898
2899 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2900 grub_env_set(args[1], buf);
2901
2902 fail:
2903
2904 check_free(device_name, grub_free);
2905 check_free(dev, grub_device_close);
2906
2907 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2908 }
2909
2910 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2911 {
2912 grub_disk_t disk;
2913 char *device_name;
2914 char *pos;
2915 char *pos2;
2916
2917 device_name = grub_file_get_device_name(filename);
2918 if (!device_name)
2919 {
2920 return 1;
2921 }
2922
2923 pos = device_name;
2924 if (pos[0] == '(')
2925 {
2926 pos++;
2927 }
2928
2929 pos2 = grub_strstr(pos, ",");
2930 if (!pos2)
2931 {
2932 pos2 = grub_strstr(pos, ")");
2933 }
2934
2935 if (pos2)
2936 {
2937 *pos2 = 0;
2938 }
2939
2940 disk = grub_disk_open(pos);
2941 if (disk)
2942 {
2943 grub_disk_read(disk, 0, 0x180, 16, guid);
2944 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2945 grub_disk_close(disk);
2946 }
2947 else
2948 {
2949 return 1;
2950 }
2951
2952 grub_free(device_name);
2953 return 0;
2954 }
2955
2956 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2957 {
2958 eltorito_descriptor desc;
2959
2960 grub_memset(&desc, 0, sizeof(desc));
2961 grub_file_seek(file, 17 * 2048);
2962 grub_file_read(file, &desc, sizeof(desc));
2963
2964 if (desc.type != 0 || desc.version != 1)
2965 {
2966 return 0;
2967 }
2968
2969 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2970 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2971 {
2972 return 0;
2973 }
2974
2975 return desc.sector;
2976 }
2977
2978 static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector)
2979 {
2980 grub_uint8_t buf[512];
2981
2982 grub_file_seek(file, sector * 2048);
2983 grub_file_read(file, buf, sizeof(buf));
2984
2985 if (buf[0] == 0x01 && buf[1] == 0x00 &&
2986 buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88)
2987 {
2988 return *((grub_uint32_t *)(buf + 40));
2989 }
2990
2991 return 0;
2992 }
2993
2994 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2995 {
2996 int i;
2997 int x86count = 0;
2998 grub_uint8_t buf[512];
2999 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
3000
3001 grub_file_seek(file, sector * 2048);
3002 grub_file_read(file, buf, sizeof(buf));
3003
3004 if (buf[0] == 0x01 && buf[1] == 0xEF)
3005 {
3006 debug("%s efi eltorito in Validation Entry\n", file->name);
3007 return 1;
3008 }
3009
3010 if (buf[0] == 0x01 && buf[1] == 0x00)
3011 {
3012 x86count++;
3013 }
3014
3015 for (i = 64; i < (int)sizeof(buf); i += 32)
3016 {
3017 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
3018 {
3019 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3020 return 1;
3021 }
3022
3023 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
3024 {
3025 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3026 return 1;
3027 }
3028 }
3029
3030 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
3031 {
3032 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
3033 {
3034 if (buf[36] == parttype[i])
3035 {
3036 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
3037 return 1;
3038 }
3039 }
3040 }
3041
3042 debug("%s does not contain efi eltorito\n", file->name);
3043 return 0;
3044 }
3045
3046 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
3047 {
3048 char *pos;
3049 const char *fs = NULL;
3050 const char *val = NULL;
3051 const char *cdprompt = NULL;
3052 grub_uint32_t i;
3053 grub_uint8_t chksum = 0;
3054 grub_disk_t disk;
3055
3056 disk = file->device->disk;
3057 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
3058
3059 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
3060 param->vtoy_disk_part_id = disk->partition->number + 1;
3061 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
3062
3063 pos = grub_strstr(file->name, "/");
3064 if (!pos)
3065 {
3066 pos = file->name;
3067 }
3068
3069 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
3070
3071 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
3072
3073 param->vtoy_img_size = file->size;
3074
3075 param->vtoy_reserved[0] = g_ventoy_break_level;
3076 param->vtoy_reserved[1] = g_ventoy_debug_level;
3077
3078 param->vtoy_reserved[2] = g_ventoy_chain_type;
3079
3080 /* Windows CD/DVD prompt 0:suppress 1:reserved */
3081 param->vtoy_reserved[4] = 0;
3082 if (g_ventoy_chain_type == 1) /* Windows */
3083 {
3084 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
3085 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
3086 {
3087 param->vtoy_reserved[4] = 1;
3088 }
3089 }
3090
3091 fs = ventoy_get_env("ventoy_fs_probe");
3092 if (fs && grub_strcmp(fs, "udf") == 0)
3093 {
3094 param->vtoy_reserved[3] = 1;
3095 }
3096
3097 param->vtoy_reserved[5] = 0;
3098 val = ventoy_get_env("VTOY_LINUX_REMOUNT");
3099 if (val && val[0] == '1' && val[1] == 0)
3100 {
3101 param->vtoy_reserved[5] = 1;
3102 }
3103
3104 /* ventoy_disk_signature used for vlnk */
3105 param->vtoy_reserved[6] = file->vlnk;
3106 grub_memcpy(param->vtoy_reserved + 7, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
3107
3108 /* calculate checksum */
3109 for (i = 0; i < sizeof(ventoy_os_param); i++)
3110 {
3111 chksum += *((grub_uint8_t *)param + i);
3112 }
3113 param->chksum = (grub_uint8_t)(0x100 - chksum);
3114
3115 return;
3116 }
3117
3118 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3119 {
3120 grub_uint32_t i = 0;
3121 grub_uint64_t total = 0;
3122 grub_uint64_t fileblk = 0;
3123 ventoy_img_chunk *chunk = NULL;
3124
3125 for (i = 0; i < chunklist->cur_chunk; i++)
3126 {
3127 chunk = chunklist->chunk + i;
3128
3129 if (chunk->disk_start_sector <= start)
3130 {
3131 debug("%u disk start invalid %lu\n", i, (ulong)start);
3132 return 1;
3133 }
3134
3135 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
3136 }
3137
3138 fileblk = (file->size + 511) / 512;
3139
3140 if (total != fileblk)
3141 {
3142 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
3143 if ((file->size % 512) && (total + 1 == fileblk))
3144 {
3145 debug("maybe img file to be processed.\n");
3146 return 0;
3147 }
3148
3149 return 1;
3150 }
3151
3152 return 0;
3153 }
3154
3155 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3156 {
3157 int fs_type;
3158 int len;
3159 grub_uint32_t i = 0;
3160 grub_uint32_t sector = 0;
3161 grub_uint32_t count = 0;
3162 grub_off_t size = 0;
3163 grub_off_t read = 0;
3164
3165 fs_type = ventoy_get_fs_type(file->fs->name);
3166 if (fs_type == ventoy_fs_exfat)
3167 {
3168 grub_fat_get_file_chunk(start, file, chunklist);
3169 }
3170 else if (fs_type == ventoy_fs_ext)
3171 {
3172 grub_ext_get_file_chunk(start, file, chunklist);
3173 }
3174 else
3175 {
3176 file->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read;
3177 file->read_hook_data = chunklist;
3178
3179 for (size = file->size; size > 0; size -= read)
3180 {
3181 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
3182 grub_file_read(file, NULL, read);
3183 }
3184
3185 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
3186 {
3187 chunklist->chunk[i].disk_start_sector += start;
3188 chunklist->chunk[i].disk_end_sector += start;
3189 }
3190
3191 if (ventoy_fs_udf == fs_type)
3192 {
3193 for (i = 0; i < chunklist->cur_chunk; i++)
3194 {
3195 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
3196 chunklist->chunk[i].img_start_sector = sector;
3197 chunklist->chunk[i].img_end_sector = sector + count - 1;
3198 sector += count;
3199 }
3200 }
3201 }
3202
3203 len = (int)grub_strlen(file->name);
3204 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
3205 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
3206 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
3207 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
3208 {
3209 for (i = 0; i < chunklist->cur_chunk; i++)
3210 {
3211 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
3212 if (count < 4)
3213 {
3214 count = 1;
3215 }
3216 else
3217 {
3218 count >>= 2;
3219 }
3220
3221 chunklist->chunk[i].img_start_sector = sector;
3222 chunklist->chunk[i].img_end_sector = sector + count - 1;
3223 sector += count;
3224 }
3225 }
3226
3227 return 0;
3228 }
3229
3230 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3231 {
3232 int rc;
3233 grub_file_t file;
3234 grub_disk_addr_t start;
3235
3236 (void)ctxt;
3237 (void)argc;
3238
3239 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3240 if (!file)
3241 {
3242 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3243 }
3244
3245 g_conf_replace_node = NULL;
3246 g_conf_replace_offset = 0;
3247
3248 if (g_img_chunk_list.chunk)
3249 {
3250 grub_free(g_img_chunk_list.chunk);
3251 }
3252
3253 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
3254 {
3255 grub_file_close(file);
3256 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
3257 }
3258
3259 /* get image chunk data */
3260 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
3261 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3262 if (NULL == g_img_chunk_list.chunk)
3263 {
3264 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3265 }
3266
3267 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
3268 g_img_chunk_list.cur_chunk = 0;
3269
3270 start = file->device->disk->partition->start;
3271
3272 ventoy_get_block_list(file, &g_img_chunk_list, start);
3273
3274 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
3275 grub_file_close(file);
3276
3277 if (rc)
3278 {
3279 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
3280 }
3281
3282 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
3283 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
3284 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3285 }
3286
3287 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
3288 {
3289 grub_uint64_t offset = 0;
3290 grub_uint32_t align = 0;
3291 grub_file_t file = NULL;
3292 conf_replace *node = NULL;
3293
3294 (void)ctxt;
3295 (void)argc;
3296 (void)args;
3297
3298 debug("select conf replace argc:%d\n", argc);
3299
3300 if (argc < 2)
3301 {
3302 return 0;
3303 }
3304
3305 node = ventoy_plugin_find_conf_replace(args[1]);
3306 if (!node)
3307 {
3308 debug("Conf replace not found for %s\n", args[1]);
3309 goto end;
3310 }
3311
3312 debug("Find conf replace for %s\n", args[1]);
3313
3314 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3315 if (file)
3316 {
3317 offset = grub_iso9660_get_last_file_dirent_pos(file);
3318 grub_file_close(file);
3319 }
3320 else if (node->img > 0)
3321 {
3322 offset = 0;
3323 }
3324 else
3325 {
3326 debug("<(loop)%s> NOT exist\n", node->orgconf);
3327 goto end;
3328 }
3329
3330 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3331 if (!file)
3332 {
3333 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3334 goto end;
3335 }
3336
3337 align = ((int)file->size + 2047) / 2048 * 2048;
3338
3339 if (align > vtoy_max_replace_file_size)
3340 {
3341 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3342 goto end;
3343 }
3344
3345 grub_file_read(file, g_conf_replace_new_buf, file->size);
3346 g_conf_replace_new_len = (int)file->size;
3347 g_conf_replace_new_len_align = align;
3348
3349 g_conf_replace_node = node;
3350 g_conf_replace_offset = offset + 2;
3351
3352 if (node->img > 0)
3353 {
3354 g_grub_param->img_replace.magic = GRUB_IMG_REPLACE_MAGIC;
3355 g_grub_param->img_replace.old_name_cnt = 1;
3356 grub_snprintf(g_grub_param->img_replace.old_file_name[0], 256, "%s", node->orgconf);
3357 }
3358
3359 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
3360
3361 end:
3362 if (file)
3363 {
3364 grub_file_close(file);
3365 }
3366 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3367 }
3368
3369 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3370 {
3371 int i = 0;
3372 int pos = 0;
3373 int defidx = 1;
3374 char *buf = NULL;
3375 char configfile[128];
3376 install_template *node = NULL;
3377
3378 (void)ctxt;
3379 (void)argc;
3380 (void)args;
3381
3382 debug("select auto installation argc:%d\n", argc);
3383
3384 if (argc < 1)
3385 {
3386 return 0;
3387 }
3388
3389 node = ventoy_plugin_find_install_template(args[0]);
3390 if (!node)
3391 {
3392 debug("Auto install template not found for %s\n", args[0]);
3393 return 0;
3394 }
3395
3396 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3397 {
3398 defidx = node->autosel;
3399 if (node->timeout < 0)
3400 {
3401 node->cursel = node->autosel - 1;
3402 debug("Auto install template auto select %d\n", node->autosel);
3403 return 0;
3404 }
3405 }
3406
3407 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3408 if (!buf)
3409 {
3410 return 0;
3411 }
3412
3413 if (node->timeout > 0)
3414 {
3415 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3416 }
3417
3418 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3419 " echo %s\n}\n", "");
3420
3421 for (i = 0; i < node->templatenum; i++)
3422 {
3423 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\"{\n"
3424 " echo \"\"\n}\n",
3425 node->templatepath[i].path);
3426 }
3427
3428 g_ventoy_menu_esc = 1;
3429 g_ventoy_suppress_esc = 1;
3430 g_ventoy_suppress_esc_default = defidx;
3431
3432 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3433 grub_script_execute_sourcecode(configfile);
3434
3435 g_ventoy_menu_esc = 0;
3436 g_ventoy_suppress_esc = 0;
3437 g_ventoy_suppress_esc_default = 1;
3438
3439 grub_free(buf);
3440
3441 node->cursel = g_ventoy_last_entry - 1;
3442
3443 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3444 }
3445
3446 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3447 {
3448 int i = 0;
3449 int pos = 0;
3450 int defidx = 1;
3451 char *buf = NULL;
3452 char configfile[128];
3453 persistence_config *node;
3454
3455 (void)ctxt;
3456 (void)argc;
3457 (void)args;
3458
3459 debug("select persistence argc:%d\n", argc);
3460
3461 if (argc < 1)
3462 {
3463 return 0;
3464 }
3465
3466 node = ventoy_plugin_find_persistent(args[0]);
3467 if (!node)
3468 {
3469 debug("Persistence image not found for %s\n", args[0]);
3470 return 0;
3471 }
3472
3473 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3474 {
3475 defidx = node->autosel;
3476 if (node->timeout < 0)
3477 {
3478 node->cursel = node->autosel - 1;
3479 debug("Persistence image auto select %d\n", node->autosel);
3480 return 0;
3481 }
3482 }
3483
3484 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3485 if (!buf)
3486 {
3487 return 0;
3488 }
3489
3490 if (node->timeout > 0)
3491 {
3492 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3493 }
3494
3495 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3496 " echo %s\n}\n", "");
3497
3498 for (i = 0; i < node->backendnum; i++)
3499 {
3500 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3501 " echo \"\"\n}\n",
3502 node->backendpath[i].path);
3503
3504 }
3505
3506 g_ventoy_menu_esc = 1;
3507 g_ventoy_suppress_esc = 1;
3508 g_ventoy_suppress_esc_default = defidx;
3509
3510 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3511 grub_script_execute_sourcecode(configfile);
3512
3513 g_ventoy_menu_esc = 0;
3514 g_ventoy_suppress_esc = 0;
3515 g_ventoy_suppress_esc_default = 1;
3516
3517 grub_free(buf);
3518
3519 node->cursel = g_ventoy_last_entry - 1;
3520
3521 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3522 }
3523
3524 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3525 {
3526 grub_uint32_t i;
3527 ventoy_img_chunk *cur;
3528
3529 (void)ctxt;
3530 (void)argc;
3531 (void)args;
3532
3533 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3534 {
3535 cur = g_img_chunk_list.chunk + i;
3536 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3537 cur->img_start_sector, cur->img_end_sector,
3538 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3539 );
3540 }
3541
3542 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3543 }
3544
3545 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3546 {
3547 grub_uint32_t i;
3548 grub_file_t file;
3549 ventoy_img_chunk_list chunklist;
3550
3551 (void)ctxt;
3552 (void)argc;
3553
3554 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3555 if (!file)
3556 {
3557 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3558 }
3559
3560 /* get image chunk data */
3561 grub_memset(&chunklist, 0, sizeof(chunklist));
3562 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3563 if (NULL == chunklist.chunk)
3564 {
3565 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3566 }
3567
3568 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3569 chunklist.cur_chunk = 0;
3570
3571 ventoy_get_block_list(file, &chunklist, 0);
3572
3573 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3574 {
3575 grub_printf("########## UNSUPPORTED ###############\n");
3576 }
3577
3578 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3579
3580 for (i = 0; i < chunklist.cur_chunk; i++)
3581 {
3582 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3583 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3584 }
3585
3586 grub_printf("\n==================================\n");
3587
3588 for (i = 0; i < chunklist.cur_chunk; i++)
3589 {
3590 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3591 (ulonglong)chunklist.chunk[i].img_start_sector,
3592 (ulonglong)chunklist.chunk[i].img_end_sector,
3593 (ulonglong)chunklist.chunk[i].disk_start_sector,
3594 (ulonglong)chunklist.chunk[i].disk_end_sector
3595 );
3596 }
3597
3598 grub_free(chunklist.chunk);
3599 grub_file_close(file);
3600
3601 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3602 }
3603
3604 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3605 {
3606 int i;
3607 ventoy_grub_param_file_replace *replace = NULL;
3608
3609 (void)ctxt;
3610 (void)argc;
3611 (void)args;
3612
3613 if (argc >= 2)
3614 {
3615 replace = &(g_grub_param->file_replace);
3616 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3617
3618 replace->old_name_cnt = 0;
3619 for (i = 0; i < 4 && i + 1 < argc; i++)
3620 {
3621 replace->old_name_cnt++;
3622 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3623 }
3624
3625 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3626 }
3627
3628 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3629 }
3630
3631 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3632 {
3633 char buf[32];
3634 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3635
3636 (void)ctxt;
3637
3638 if (argc >= 1)
3639 {
3640 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3641 grub_env_set(args[0], buf);
3642 }
3643
3644 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3645 }
3646
3647 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3648 {
3649 (void)ctxt;
3650 (void)argc;
3651 (void)args;
3652
3653 if (argc == 0)
3654 {
3655 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3656 grub_printf("%s", g_list_script_buf);
3657 }
3658 else
3659 {
3660 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3661 grub_printf("%s", g_tree_script_buf);
3662 }
3663
3664 return 0;
3665 }
3666
3667 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3668 {
3669 img_info *cur = g_ventoy_img_list;
3670
3671 (void)ctxt;
3672 (void)argc;
3673 (void)args;
3674
3675 while (cur)
3676 {
3677 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3678 grub_printf("name:<%s>\n\n", cur->name);
3679 cur = cur->next;
3680 }
3681
3682 return 0;
3683 }
3684
3685 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3686 {
3687 (void)ctxt;
3688 (void)argc;
3689 (void)args;
3690
3691 ventoy_plugin_dump_injection();
3692
3693 return 0;
3694 }
3695
3696 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3697 {
3698 (void)ctxt;
3699 (void)argc;
3700 (void)args;
3701
3702 ventoy_plugin_dump_auto_install();
3703
3704 return 0;
3705 }
3706
3707 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3708 {
3709 (void)ctxt;
3710 (void)argc;
3711 (void)args;
3712
3713 ventoy_plugin_dump_persistence();
3714
3715 return 0;
3716 }
3717
3718 static int ventoy_check_mode_by_name(char *filename, const char *suffix)
3719 {
3720 int i;
3721 int len1;
3722 int len2;
3723
3724 len1 = (int)grub_strlen(filename);
3725 len2 = (int)grub_strlen(suffix);
3726
3727 if (len1 <= len2)
3728 {
3729 return 0;
3730 }
3731
3732 for (i = len1 - 1; i >= 0; i--)
3733 {
3734 if (filename[i] == '.')
3735 {
3736 break;
3737 }
3738 }
3739
3740 if (i < len2 + 1)
3741 {
3742 return 0;
3743 }
3744
3745 if (filename[i - len2 - 1] != '_')
3746 {
3747 return 0;
3748 }
3749
3750 if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0)
3751 {
3752 return 1;
3753 }
3754
3755 return 0;
3756 }
3757
3758 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3759 {
3760 (void)ctxt;
3761 (void)argc;
3762 (void)args;
3763
3764 if (argc != 1 && argc != 2)
3765 {
3766 return 1;
3767 }
3768
3769 if (args[0][0] == '0')
3770 {
3771 if (g_ventoy_memdisk_mode)
3772 {
3773 return 0;
3774 }
3775
3776 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk"))
3777 {
3778 return 0;
3779 }
3780
3781 return 1;
3782 }
3783 else if (args[0][0] == '1')
3784 {
3785 return g_ventoy_iso_raw ? 0 : 1;
3786 }
3787 else if (args[0][0] == '2')
3788 {
3789 return g_ventoy_iso_uefi_drv ? 0 : 1;
3790 }
3791 else if (args[0][0] == '3')
3792 {
3793 if (g_ventoy_grub2_mode)
3794 {
3795 return 0;
3796 }
3797
3798 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2"))
3799 {
3800 return 0;
3801 }
3802
3803 return 1;
3804 }
3805 else if (args[0][0] == '4')
3806 {
3807 if (g_ventoy_wimboot_mode)
3808 {
3809 return 0;
3810 }
3811
3812 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot"))
3813 {
3814 return 0;
3815 }
3816
3817 return 1;
3818 }
3819
3820 return 1;
3821 }
3822
3823 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3824 {
3825 static int configfile_mode = 0;
3826 char memfile[128] = {0};
3827
3828 (void)ctxt;
3829 (void)argc;
3830 (void)args;
3831
3832 /*
3833 * args[0]: 0:normal 1:configfile
3834 * args[1]: 0:list_buf 1:tree_buf
3835 */
3836
3837 if (argc != 2)
3838 {
3839 debug("Invalid argc %d\n", argc);
3840 return 0;
3841 }
3842
3843 VTOY_CMD_CHECK(1);
3844
3845 if (args[0][0] == '0')
3846 {
3847 if (args[1][0] == '0')
3848 {
3849 grub_script_execute_sourcecode(g_list_script_buf);
3850 }
3851 else
3852 {
3853 grub_script_execute_sourcecode(g_tree_script_buf);
3854 }
3855 }
3856 else
3857 {
3858 if (configfile_mode)
3859 {
3860 debug("Now already in F3 mode %d\n", configfile_mode);
3861 return 0;
3862 }
3863
3864 if (args[1][0] == '0')
3865 {
3866 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3867 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3868 }
3869 else
3870 {
3871 g_ventoy_last_entry = -1;
3872 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3873 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3874 }
3875
3876 configfile_mode = 1;
3877 grub_script_execute_sourcecode(memfile);
3878 configfile_mode = 0;
3879 }
3880
3881 return 0;
3882 }
3883
3884 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3885 {
3886 grub_file_t file;
3887
3888 (void)ctxt;
3889
3890 if (argc != 1)
3891 {
3892 return 1;
3893 }
3894
3895 g_ventoy_case_insensitive = 1;
3896 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3897 g_ventoy_case_insensitive = 0;
3898
3899 grub_errno = 0;
3900
3901 if (file)
3902 {
3903 grub_file_close(file);
3904 return 0;
3905 }
3906 return 1;
3907 }
3908
3909 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3910 {
3911 int id = 0;
3912 int find = 0;
3913 grub_disk_t disk;
3914 const char *isopath = NULL;
3915 char hdname[32];
3916 ventoy_mbr_head mbr;
3917
3918 (void)ctxt;
3919 (void)argc;
3920
3921 if (argc != 1)
3922 {
3923 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3924 }
3925
3926 isopath = grub_env_get("vtoy_iso_part");
3927 if (!isopath)
3928 {
3929 debug("isopath is null %p\n", isopath);
3930 return 0;
3931 }
3932
3933 debug("isopath is %s\n", isopath);
3934
3935 for (id = 0; id < 30 && (find == 0); id++)
3936 {
3937 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3938 if (grub_strstr(isopath, hdname))
3939 {
3940 debug("skip %s ...\n", hdname);
3941 continue;
3942 }
3943
3944 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3945
3946 disk = grub_disk_open(hdname);
3947 if (!disk)
3948 {
3949 debug("%s not exist\n", hdname);
3950 break;
3951 }
3952
3953 grub_memset(&mbr, 0, sizeof(mbr));
3954 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3955 {
3956 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3957 {
3958 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3959 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3960 {
3961
3962 grub_env_set(args[0], hdname);
3963 find = 1;
3964 }
3965 }
3966 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3967 }
3968 else
3969 {
3970 debug("read %s failed\n", hdname);
3971 }
3972
3973 grub_disk_close(disk);
3974 }
3975
3976 return 0;
3977 }
3978
3979 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3980 {
3981 int len = 1024;
3982 grub_file_t file;
3983 char *buf = NULL;
3984
3985 (void)ctxt;
3986 (void)argc;
3987
3988 if (argc != 2)
3989 {
3990 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3991 }
3992
3993 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3994 if (!file)
3995 {
3996 debug("failed to open file %s\n", args[0]);
3997 return 0;
3998 }
3999
4000 buf = grub_malloc(len);
4001 if (!buf)
4002 {
4003 goto end;
4004 }
4005
4006 buf[len - 1] = 0;
4007 grub_file_read(file, buf, len - 1);
4008
4009 ventoy_get_line(buf);
4010 ventoy_set_env(args[1], buf);
4011
4012 end:
4013
4014 grub_check_free(buf);
4015 grub_file_close(file);
4016
4017 return 0;
4018 }
4019
4020 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
4021 {
4022 grub_uint64_t end_max = 0;
4023 int *pCnt = (int *)data;
4024
4025 (void)disk;
4026
4027 (*pCnt)++;
4028 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
4029 "0 %llu linear /dev/ventoy %llu\n",
4030 (ulonglong)partition->len, (ulonglong)partition->start);
4031
4032 end_max = (partition->len + partition->start) * 512;
4033 if (end_max > g_part_end_max)
4034 {
4035 g_part_end_max = end_max;
4036 }
4037
4038 return 0;
4039 }
4040
4041 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
4042 {
4043 int cnt = 0;
4044 char *device_name = NULL;
4045 grub_device_t dev = NULL;
4046 char buf[64];
4047
4048 (void)ctxt;
4049
4050 g_part_list_pos = 0;
4051 g_part_end_max = 0;
4052 grub_env_unset("vtoy_img_part_file");
4053
4054 if (argc != 1)
4055 {
4056 return 1;
4057 }
4058
4059 device_name = grub_file_get_device_name(args[0]);
4060 if (!device_name)
4061 {
4062 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
4063 goto end;
4064 }
4065
4066 dev = grub_device_open(device_name);
4067 if (!dev)
4068 {
4069 debug("grub_device_open failed, %s\n", device_name);
4070 goto end;
4071 }
4072
4073 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
4074
4075 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
4076 grub_env_set("vtoy_img_part_file", buf);
4077
4078 grub_snprintf(buf, sizeof(buf), "%d", cnt);
4079 grub_env_set("vtoy_img_part_cnt", buf);
4080
4081 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max);
4082 grub_env_set("vtoy_img_max_part_end", buf);
4083
4084 end:
4085
4086 check_free(device_name, grub_free);
4087 check_free(dev, grub_device_close);
4088
4089 return 0;
4090 }
4091
4092
4093 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
4094 {
4095 int rc = 1;
4096 grub_file_t file;
4097 char *buf = NULL;
4098
4099 (void)ctxt;
4100 (void)argc;
4101
4102 if (argc != 2)
4103 {
4104 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
4105 }
4106
4107 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4108 if (!file)
4109 {
4110 debug("failed to open file %s\n", args[0]);
4111 return 1;
4112 }
4113
4114 buf = grub_malloc(file->size + 1);
4115 if (!buf)
4116 {
4117 goto end;
4118 }
4119
4120 buf[file->size] = 0;
4121 grub_file_read(file, buf, file->size);
4122
4123 if (grub_strstr(buf, args[1]))
4124 {
4125 rc = 0;
4126 }
4127
4128 end:
4129
4130 grub_check_free(buf);
4131 grub_file_close(file);
4132
4133 return rc;
4134 }
4135
4136 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
4137 {
4138 int len;
4139 grub_file_t file;
4140 char buf[64];
4141 grub_uint64_t size;
4142 ventoy_iso9660_vd pvd;
4143
4144 (void)ctxt;
4145 (void)argc;
4146
4147 if (argc != 4)
4148 {
4149 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
4150 }
4151
4152 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4153 if (!file)
4154 {
4155 debug("failed to open file %s\n", args[0]);
4156 return 0;
4157 }
4158
4159 grub_file_seek(file, 16 * 2048);
4160 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
4161 if (len != sizeof(pvd))
4162 {
4163 debug("failed to read pvd %d\n", len);
4164 goto end;
4165 }
4166
4167 grub_memset(buf, 0, sizeof(buf));
4168 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
4169 ventoy_set_env(args[1], buf);
4170
4171 grub_memset(buf, 0, sizeof(buf));
4172 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
4173 ventoy_set_env(args[2], buf);
4174
4175 size = pvd.space;
4176 size *= 2048;
4177 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
4178 ventoy_set_env(args[3], buf);
4179
4180 end:
4181 grub_file_close(file);
4182
4183 return 0;
4184 }
4185
4186 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
4187 {
4188 int len;
4189 grub_file_t file;
4190 char buf[64];
4191
4192 (void)ctxt;
4193 (void)argc;
4194
4195 if (argc != 2)
4196 {
4197 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
4198 }
4199
4200 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4201 if (!file)
4202 {
4203 debug("failed to open file %s\n", args[0]);
4204 return 0;
4205 }
4206
4207 grub_memset(buf, 0, sizeof(buf));
4208 grub_file_seek(file, 16 * 2048 + 813);
4209 len = (int)grub_file_read(file, buf, 17);
4210 if (len != 17)
4211 {
4212 debug("failed to read create date %d\n", len);
4213 goto end;
4214 }
4215
4216 ventoy_set_env(args[1], buf);
4217
4218 end:
4219 grub_file_close(file);
4220
4221 return 0;
4222 }
4223
4224 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4225 {
4226 (void)ctxt;
4227 (void)argc;
4228 (void)args;
4229
4230 ventoy_env_hook_root(1);
4231
4232 return 0;
4233 }
4234
4235 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4236 {
4237 (void)ctxt;
4238 (void)argc;
4239 (void)args;
4240
4241 ventoy_env_hook_root(0);
4242
4243 return 0;
4244 }
4245
4246 #ifdef GRUB_MACHINE_EFI
4247 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4248 {
4249 int ret = 1;
4250 grub_uint8_t *var;
4251 grub_size_t size;
4252 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4253
4254 (void)ctxt;
4255 (void)argc;
4256 (void)args;
4257
4258 var = grub_efi_get_variable("SecureBoot", &global, &size);
4259 if (var && *var == 1)
4260 {
4261 return 0;
4262 }
4263
4264 return ret;
4265 }
4266 #else
4267 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4268 {
4269 (void)ctxt;
4270 (void)argc;
4271 (void)args;
4272 return 1;
4273 }
4274 #endif
4275
4276 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
4277 {
4278 int i;
4279 int ret = 1;
4280 grub_file_t file;
4281 grub_uint64_t FileSectors = 0;
4282 ventoy_gpt_info *gpt = NULL;
4283 ventoy_part_table *pt = NULL;
4284 grub_uint8_t zeroguid[16] = {0};
4285
4286 (void)ctxt;
4287 (void)argc;
4288
4289 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4290 if (!file)
4291 {
4292 debug("failed to open file %s\n", args[0]);
4293 return 1;
4294 }
4295
4296 if (file->size % 512)
4297 {
4298 debug("unaligned file size: %llu\n", (ulonglong)file->size);
4299 goto out;
4300 }
4301
4302 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
4303 if (!gpt)
4304 {
4305 goto out;
4306 }
4307
4308 FileSectors = file->size / 512;
4309
4310 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
4311 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
4312 {
4313 debug("This is EFI partition table\n");
4314
4315 for (i = 0; i < 128; i++)
4316 {
4317 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
4318 {
4319 if (FileSectors < gpt->PartTbl[i].LastLBA)
4320 {
4321 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4322 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
4323 goto out;
4324 }
4325 }
4326 }
4327 }
4328 else
4329 {
4330 debug("This is MBR partition table\n");
4331
4332 for (i = 0; i < 4; i++)
4333 {
4334 pt = gpt->MBR.PartTbl + i;
4335 if (FileSectors < pt->StartSectorId + pt->SectorCount)
4336 {
4337 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4338 (ulonglong)(pt->StartSectorId + pt->SectorCount),
4339 (ulonglong)FileSectors);
4340 goto out;
4341 }
4342 }
4343 }
4344
4345 ret = 0;
4346
4347 out:
4348 grub_file_close(file);
4349 grub_check_free(gpt);
4350 grub_errno = GRUB_ERR_NONE;
4351 return ret;
4352 }
4353
4354 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
4355 {
4356 int i;
4357 int ret;
4358
4359 (void)ctxt;
4360 (void)argc;
4361 (void)args;
4362
4363 for (i = 0; i < 500; i++)
4364 {
4365 ret = grub_getkey_noblock();
4366 if (ret == GRUB_TERM_NO_KEY)
4367 {
4368 break;
4369 }
4370 }
4371
4372 if (i >= 500)
4373 {
4374 grub_cls();
4375 grub_printf("\n\n Still have key input after clear.\n");
4376 grub_refresh();
4377 grub_sleep(5);
4378 }
4379
4380 return 0;
4381 }
4382
4383 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4384 {
4385 int i;
4386 int buflen;
4387 int datalen;
4388 int loclen;
4389 int img_chunk_num;
4390 int image_sector_size;
4391 char cmd[64];
4392 ventoy_chain_head *chain;
4393 ventoy_img_chunk *chunk;
4394 ventoy_os_param *osparam;
4395 ventoy_image_location *location;
4396 ventoy_image_disk_region *region;
4397 struct grub_acpi_table_header *acpi;
4398
4399 (void)ctxt;
4400
4401 if (argc != 2)
4402 {
4403 return 1;
4404 }
4405
4406 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4407
4408 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4409 if (!chain)
4410 {
4411 return 1;
4412 }
4413
4414 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4415
4416 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4417 {
4418 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4419 return 1;
4420 }
4421
4422 img_chunk_num = chain->img_chunk_num;
4423
4424 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4425 datalen = sizeof(ventoy_os_param) + loclen;
4426
4427 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4428 acpi = grub_zalloc(buflen);
4429 if (!acpi)
4430 {
4431 return 1;
4432 }
4433
4434 /* Step1: Fill acpi table header */
4435 grub_memcpy(acpi->signature, "VTOY", 4);
4436 acpi->length = buflen;
4437 acpi->revision = 1;
4438 grub_memcpy(acpi->oemid, "VENTOY", 6);
4439 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4440 acpi->oemrev = 1;
4441 acpi->creator_id[0] = 1;
4442 acpi->creator_rev = 1;
4443
4444 /* Step2: Fill data */
4445 osparam = (ventoy_os_param *)(acpi + 1);
4446 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4447 osparam->vtoy_img_location_addr = 0;
4448 osparam->vtoy_img_location_len = loclen;
4449 osparam->chksum = 0;
4450 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4451
4452 location = (ventoy_image_location *)(osparam + 1);
4453 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4454 location->image_sector_size = image_sector_size;
4455 location->disk_sector_size = chain->disk_sector_size;
4456 location->region_count = img_chunk_num;
4457
4458 region = location->regions;
4459 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4460 if (512 == image_sector_size)
4461 {
4462 for (i = 0; i < img_chunk_num; i++)
4463 {
4464 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4465 region->image_start_sector = chunk->img_start_sector * 4;
4466 region->disk_start_sector = chunk->disk_start_sector;
4467 region++;
4468 chunk++;
4469 }
4470 }
4471 else
4472 {
4473 for (i = 0; i < img_chunk_num; i++)
4474 {
4475 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4476 region->image_start_sector = chunk->img_start_sector;
4477 region->disk_start_sector = chunk->disk_start_sector;
4478 region++;
4479 chunk++;
4480 }
4481 }
4482
4483 /* Step3: Fill acpi checksum */
4484 acpi->checksum = 0;
4485 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4486
4487 /* load acpi table */
4488 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4489 grub_script_execute_sourcecode(cmd);
4490
4491 grub_free(acpi);
4492
4493 VENTOY_CMD_RETURN(0);
4494 }
4495
4496 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4497 {
4498 (void)ctxt;
4499 (void)argc;
4500 (void)args;
4501
4502 g_ventoy_last_entry_back = g_ventoy_last_entry;
4503 g_ventoy_last_entry = -1;
4504
4505 return 0;
4506 }
4507
4508 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4509 {
4510 (void)ctxt;
4511 (void)argc;
4512 (void)args;
4513
4514 g_ventoy_last_entry = g_ventoy_last_entry_back;
4515
4516 return 0;
4517 }
4518
4519 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4520 {
4521 const char *pos = filename + 1;
4522
4523 if (info->dir)
4524 {
4525 while (*pos)
4526 {
4527 if (*pos == '.')
4528 {
4529 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4530 {
4531 grub_strncpy((char *)data, filename, 128);
4532 return 1;
4533 }
4534 }
4535 pos++;
4536 }
4537 }
4538
4539 return 0;
4540 }
4541
4542 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4543 {
4544 int rc = 1;
4545 char *device_name = NULL;
4546 grub_device_t dev = NULL;
4547 grub_fs_t fs = NULL;
4548 char buf[128] = {0};
4549
4550 (void)ctxt;
4551
4552 if (argc != 3)
4553 {
4554 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4555 return 1;
4556 }
4557
4558 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4559
4560 device_name = grub_file_get_device_name(args[0]);
4561 if (!device_name)
4562 {
4563 debug("grub_file_get_device_name failed, %s\n", args[0]);
4564 goto end;
4565 }
4566
4567 dev = grub_device_open(device_name);
4568 if (!dev)
4569 {
4570 debug("grub_device_open failed, %s\n", device_name);
4571 goto end;
4572 }
4573
4574 fs = grub_fs_probe(dev);
4575 if (!fs)
4576 {
4577 debug("grub_fs_probe failed, %s\n", device_name);
4578 goto end;
4579 }
4580
4581 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4582
4583 if (buf[0])
4584 {
4585 ventoy_set_env(args[2], buf);
4586 }
4587
4588 rc = 0;
4589
4590 end:
4591
4592 check_free(device_name, grub_free);
4593 check_free(dev, grub_device_close);
4594
4595 return rc;
4596 }
4597
4598 int ventoy_load_part_table(const char *diskname)
4599 {
4600 char name[64];
4601 int ret;
4602 grub_disk_t disk;
4603 grub_device_t dev;
4604
4605 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4606 if (!g_ventoy_part_info)
4607 {
4608 return 1;
4609 }
4610
4611 disk = grub_disk_open(diskname);
4612 if (!disk)
4613 {
4614 debug("Failed to open disk %s\n", diskname);
4615 return 1;
4616 }
4617
4618 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4619
4620 g_ventoy_disk_bios_id = disk->id;
4621
4622 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4623 grub_disk_close(disk);
4624
4625 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4626 dev = grub_device_open(name);
4627 if (dev)
4628 {
4629 /* Check for official Ventoy device */
4630 ret = ventoy_check_official_device(dev);
4631 grub_device_close(dev);
4632
4633 if (ret)
4634 {
4635 return 1;
4636 }
4637 }
4638
4639 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4640 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4641
4642 return 0;
4643 }
4644
4645 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4646 {
4647 int ret;
4648
4649 (void)argc;
4650 (void)ctxt;
4651
4652 ret = ventoy_load_part_table(args[0]);
4653 if (ret)
4654 {
4655 grub_exit();
4656 }
4657
4658 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4659 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4660
4661 return 0;
4662 }
4663
4664 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4665 {
4666 int ret = 1;
4667 const char *vcfg = NULL;
4668
4669 (void)argc;
4670 (void)ctxt;
4671
4672 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4673 if (vcfg)
4674 {
4675 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4676 grub_env_set(args[1], vcfg);
4677 ret = 0;
4678 }
4679 else
4680 {
4681 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4682 }
4683
4684 grub_errno = 0;
4685 return ret;
4686 }
4687
4688
4689 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4690 {
4691 int id;
4692 grub_uint8_t zeroguid[16] = {0};
4693
4694 (void)argc;
4695 (void)ctxt;
4696
4697 id = (int)grub_strtoul(args[0], NULL, 10);
4698 grub_errno = 0;
4699
4700 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4701 {
4702 if (id >= 1 && id <= 128)
4703 {
4704 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4705 {
4706 return 0;
4707 }
4708 }
4709 }
4710 else
4711 {
4712 if (id >= 1 && id <= 4)
4713 {
4714 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4715 {
4716 return 0;
4717 }
4718 }
4719 }
4720
4721 return 1;
4722 }
4723
4724 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4725 {
4726 int rc = 1;
4727 char *device_name = NULL;
4728 grub_device_t dev = NULL;
4729 grub_fs_t fs = NULL;
4730 char *label = NULL;
4731
4732 (void)ctxt;
4733
4734 debug("get fs label for %s\n", args[0]);
4735
4736 if (argc != 2)
4737 {
4738 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4739 return 1;
4740 }
4741
4742 device_name = grub_file_get_device_name(args[0]);
4743 if (!device_name)
4744 {
4745 debug("grub_file_get_device_name failed, %s\n", args[0]);
4746 goto end;
4747 }
4748
4749 dev = grub_device_open(device_name);
4750 if (!dev)
4751 {
4752 debug("grub_device_open failed, %s\n", device_name);
4753 goto end;
4754 }
4755
4756 fs = grub_fs_probe(dev);
4757 if (NULL == fs || NULL == fs->fs_label)
4758 {
4759 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4760 goto end;
4761 }
4762
4763 fs->fs_label(dev, &label);
4764 if (label)
4765 {
4766 debug("label=<%s>\n", label);
4767 ventoy_set_env(args[1], label);
4768 grub_free(label);
4769 }
4770
4771 rc = 0;
4772
4773 end:
4774
4775 check_free(device_name, grub_free);
4776 check_free(dev, grub_device_close);
4777
4778 return rc;
4779 }
4780
4781 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4782 {
4783 if (!info->dir)
4784 {
4785 grub_snprintf((char *)data, 256, "%s", filename);
4786 return 1;
4787 }
4788
4789 return 0;
4790 }
4791
4792 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4793 {
4794 if (info->dir && filename && filename[0] != '.')
4795 {
4796 grub_snprintf((char *)data, 256, "%s", filename);
4797 return 1;
4798 }
4799
4800 return 0;
4801 }
4802
4803 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4804 {
4805 int rc = 1;
4806 char *device_name = NULL;
4807 grub_device_t dev = NULL;
4808 grub_fs_t fs = NULL;
4809 char name[256] ={0};
4810
4811 if (argc != 3)
4812 {
4813 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4814 return 1;
4815 }
4816
4817 device_name = grub_file_get_device_name(args[0]);
4818 if (!device_name)
4819 {
4820 debug("grub_file_get_device_name failed, %s\n", args[0]);
4821 goto end;
4822 }
4823
4824 dev = grub_device_open(device_name);
4825 if (!dev)
4826 {
4827 debug("grub_device_open failed, %s\n", device_name);
4828 goto end;
4829 }
4830
4831 fs = grub_fs_probe(dev);
4832 if (!fs)
4833 {
4834 debug("grub_fs_probe failed, %s\n", device_name);
4835 goto end;
4836 }
4837
4838 fs->fs_dir(dev, args[1], hook, name);
4839 if (name[0])
4840 {
4841 ventoy_set_env(args[2], name);
4842 }
4843
4844 rc = 0;
4845
4846 end:
4847
4848 check_free(device_name, grub_free);
4849 check_free(dev, grub_device_close);
4850
4851 return rc;
4852 }
4853
4854 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4855 {
4856 (void)ctxt;
4857 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4858 }
4859
4860 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4861 {
4862 (void)ctxt;
4863 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4864 }
4865
4866 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4867 {
4868 char c;
4869 char *pos = NULL;
4870 char *end = NULL;
4871
4872 (void)ctxt;
4873
4874 if (argc != 2)
4875 {
4876 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4877 return 1;
4878 }
4879
4880 for (pos = args[0]; *pos; pos++)
4881 {
4882 if (*pos == '.')
4883 {
4884 end = pos;
4885 }
4886 }
4887
4888 if (end)
4889 {
4890 c = *end;
4891 *end = 0;
4892 }
4893
4894 grub_env_set(args[1], args[0]);
4895
4896 if (end)
4897 {
4898 *end = c;
4899 }
4900
4901 return 0;
4902 }
4903
4904 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4905 {
4906 int i;
4907 int len;
4908 const char *buf;
4909
4910 (void)ctxt;
4911
4912 if (argc != 2)
4913 {
4914 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4915 return 1;
4916 }
4917
4918 buf = args[0];
4919 len = (int)grub_strlen(buf);
4920 for (i = len; i > 0; i--)
4921 {
4922 if (buf[i - 1] == '/')
4923 {
4924 grub_env_set(args[1], buf + i);
4925 return 0;
4926 }
4927 }
4928
4929 grub_env_set(args[1], buf);
4930
4931 return 0;
4932 }
4933
4934 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4935 {
4936 struct grub_video_mode_info info;
4937 char buf[32];
4938
4939 (void)ctxt;
4940 (void)argc;
4941 (void)args;
4942
4943 if (!g_video_mode_list)
4944 {
4945 ventoy_enum_video_mode();
4946 }
4947
4948 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4949 {
4950 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4951 }
4952 else
4953 {
4954 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4955 }
4956
4957 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4958
4959 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4960 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4961
4962 VENTOY_CMD_RETURN(0);
4963 }
4964
4965 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4966 {
4967 struct grub_video_mode_info info;
4968 char buf[32];
4969
4970 (void)ctxt;
4971 (void)argc;
4972 (void)args;
4973
4974 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4975 {
4976 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4977 }
4978 else
4979 {
4980 grub_snprintf(buf, sizeof(buf), "0x0x0");
4981 }
4982
4983 grub_env_set(args[0], buf);
4984
4985 VENTOY_CMD_RETURN(0);
4986 }
4987
4988 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4989 {
4990 int id;
4991 char buf[32];
4992
4993 (void)ctxt;
4994 (void)argc;
4995
4996 if (!g_video_mode_list)
4997 {
4998 return 0;
4999 }
5000
5001 id = (int)grub_strtoul(args[0], NULL, 10);
5002 if (id < g_video_mode_num)
5003 {
5004 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5005 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5006 }
5007
5008 grub_env_set(args[1], buf);
5009
5010 VENTOY_CMD_RETURN(0);
5011 }
5012
5013 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5014 {
5015 grub_uint32_t i;
5016 grub_uint32_t loadsector = 0;
5017 grub_file_t file;
5018 char value[32];
5019 grub_uint32_t boot_catlog = 0;
5020 grub_uint8_t buf[512];
5021
5022 (void)ctxt;
5023
5024 if (argc != 2)
5025 {
5026 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5027 return 1;
5028 }
5029
5030 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5031 if (!file)
5032 {
5033 debug("failed to open %s\n", args[0]);
5034 return 1;
5035 }
5036
5037 boot_catlog = ventoy_get_iso_boot_catlog(file);
5038 if (boot_catlog == 0)
5039 {
5040 debug("No bootcatlog found\n");
5041 grub_file_close(file);
5042 return 1;
5043 }
5044
5045 grub_memset(buf, 0, sizeof(buf));
5046 grub_file_seek(file, boot_catlog * 2048);
5047 grub_file_read(file, buf, sizeof(buf));
5048 grub_file_close(file);
5049
5050 for (i = 0; i < sizeof(buf); i += 32)
5051 {
5052 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5053 {
5054 if (buf[i + 32] == 0x88)
5055 {
5056 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5057 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5058 break;
5059 }
5060 }
5061 }
5062
5063 if (loadsector == 0)
5064 {
5065 debug("No EFI eltorito info found\n");
5066 return 1;
5067 }
5068
5069 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5070 grub_env_set(args[1], value);
5071 VENTOY_CMD_RETURN(0);
5072 }
5073
5074 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5075 {
5076 int curpos;
5077 int printlen;
5078 grub_size_t len;
5079 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5080
5081 if (pfsdir->initrd[0])
5082 {
5083 return 1;
5084 }
5085
5086 curpos = pfsdir->curpos;
5087 len = grub_strlen(filename);
5088
5089 if (info->dir)
5090 {
5091 if ((len == 1 && filename[0] == '.') ||
5092 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5093 {
5094 return 0;
5095 }
5096
5097 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5098 pfsdir->dircnt++;
5099
5100 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5101 pfsdir->curpos = curpos + printlen;
5102 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5103 pfsdir->curpos = curpos;
5104 pfsdir->fullpath[curpos] = 0;
5105 }
5106 else
5107 {
5108 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5109 pfsdir->filecnt++;
5110
5111 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5112 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5113 {
5114 if (info->size > 32 * VTOY_SIZE_1MB)
5115 {
5116 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5117 return 1;
5118 }
5119 }
5120 }
5121
5122 return 0;
5123 }
5124
5125 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5126 {
5127 int i;
5128 char *pos = NULL;
5129 char *device_name = NULL;
5130 grub_device_t dev = NULL;
5131 grub_fs_t fs = NULL;
5132 replace_fs_dir *pfsdir = NULL;
5133
5134 (void)ctxt;
5135
5136 if (argc != 2)
5137 {
5138 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5139 return 1;
5140 }
5141
5142 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5143 if (!pfsdir)
5144 {
5145 return 1;
5146 }
5147
5148 device_name = grub_file_get_device_name(args[0]);
5149 if (!device_name)
5150 {
5151 goto fail;
5152 }
5153
5154 dev = grub_device_open(device_name);
5155 if (!dev)
5156 {
5157 goto fail;
5158 }
5159
5160 fs = grub_fs_probe(dev);
5161 if (!fs)
5162 {
5163 goto fail;
5164 }
5165
5166 pfsdir->dev = dev;
5167 pfsdir->fs = fs;
5168 pfsdir->curpos = 1;
5169 pfsdir->fullpath[0] = '/';
5170 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5171
5172 if (pfsdir->initrd[0])
5173 {
5174 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5175
5176 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5177 {
5178 if (pfsdir->initrd[i] == '/')
5179 {
5180 pfsdir->initrd[i] = '\\';
5181 }
5182 }
5183
5184 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5185 grub_env_set(args[1], pos);
5186 }
5187 else
5188 {
5189 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5190 }
5191
5192 fail:
5193
5194 grub_check_free(pfsdir);
5195 grub_check_free(device_name);
5196 check_free(dev, grub_device_close);
5197
5198 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5199 }
5200
5201 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5202 {
5203 const char *pager = NULL;
5204
5205 (void)ctxt;
5206 (void)argc;
5207 (void)args;
5208
5209 pager = grub_env_get("pager");
5210 if (NULL == pager)
5211 {
5212 g_pager_flag = 1;
5213 grub_env_set("pager", "1");
5214 }
5215 else if (pager[0] == '1')
5216 {
5217 g_pager_flag = 0;
5218 }
5219 else
5220 {
5221 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5222 g_pager_flag = 2;
5223 grub_env_set("pager", "1");
5224 }
5225
5226 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5227 }
5228
5229 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5230 {
5231 (void)ctxt;
5232 (void)argc;
5233 (void)args;
5234
5235 if (g_pager_flag == 1)
5236 {
5237 grub_env_unset("pager");
5238 }
5239 else if (g_pager_flag == 2)
5240 {
5241 grub_env_set("pager", g_old_pager);
5242 }
5243
5244 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5245 }
5246
5247 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5248 {
5249 if (g_json_case_mis_path[0])
5250 {
5251 return 1;
5252 }
5253
5254 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5255 {
5256 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5257 return 1;
5258 }
5259 return 0;
5260 }
5261
5262 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5263 {
5264 char path[16];
5265 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5266
5267 if (g_json_case_mis_path[0])
5268 {
5269 return 1;
5270 }
5271
5272 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5273 {
5274 if (grub_strcasecmp(filename, "ventoy") == 0)
5275 {
5276 grub_snprintf(path, sizeof(path), "/%s", filename);
5277 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5278 if (g_json_case_mis_path[0])
5279 {
5280 return 1;
5281 }
5282 }
5283 }
5284
5285 return 0;
5286 }
5287
5288 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5289 {
5290 int fstype = 0;
5291 char *device_name = NULL;
5292 grub_device_t dev = NULL;
5293 grub_fs_t fs = NULL;
5294 chk_case_fs_dir fs_dir;
5295
5296 (void)ctxt;
5297 (void)argc;
5298 (void)args;
5299
5300 device_name = grub_file_get_device_name(args[0]);
5301 if (!device_name)
5302 {
5303 goto out;
5304 }
5305
5306 dev = grub_device_open(device_name);
5307 if (!dev)
5308 {
5309 goto out;
5310 }
5311
5312 fs = grub_fs_probe(dev);
5313 if (!fs)
5314 {
5315 goto out;
5316 }
5317
5318 fstype = ventoy_get_fs_type(fs->name);
5319 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5320 {
5321 goto out;
5322 }
5323
5324 g_json_case_mis_path[0] = 0;
5325 fs_dir.dev = dev;
5326 fs_dir.fs = fs;
5327 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5328
5329 if (g_json_case_mis_path[0])
5330 {
5331 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5332 }
5333
5334 out:
5335
5336 grub_check_free(device_name);
5337 check_free(dev, grub_device_close);
5338
5339 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5340 }
5341
5342 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5343 {
5344 grub_disk_t disk;
5345 grub_partition_t part;
5346 char priority_str[3]; /* Maximum value 15 */
5347
5348 (void)ctxt;
5349
5350 if (argc < 2 || argc > 3)
5351 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5352 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5353
5354 /* Open the disk if it exists */
5355 disk = grub_disk_open (args[0]);
5356 if (!disk)
5357 {
5358 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5359 "Not a disk");
5360 }
5361
5362 part = grub_partition_probe (disk, args[1]);
5363 if (!part)
5364 {
5365 grub_disk_close (disk);
5366 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5367 "No such partition");
5368 }
5369
5370 if (grub_strcmp (part->partmap->name, "gpt"))
5371 {
5372 grub_disk_close (disk);
5373 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5374 "Not a GPT partition");
5375 }
5376
5377 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5378 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5379
5380 if (argc == 3)
5381 {
5382 grub_env_set (args[2], priority_str);
5383 grub_env_export (args[2]);
5384 }
5385 else
5386 {
5387 grub_printf ("Priority is %s\n", priority_str);
5388 }
5389
5390 grub_disk_close (disk);
5391 return GRUB_ERR_NONE;
5392 }
5393
5394
5395 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5396 {
5397 int ret = 1;
5398 int joliet = 0;
5399 grub_file_t file = NULL;
5400 grub_uint32_t loadrba = 0;
5401 grub_uint32_t boot_catlog = 0;
5402 grub_uint8_t sector[512];
5403 boot_info_table *info = NULL;
5404
5405 (void)ctxt;
5406 (void)argc;
5407
5408 /* This also trigger a iso9660 fs parse */
5409 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5410 {
5411 return 0;
5412 }
5413
5414 joliet = grub_iso9660_is_joliet();
5415 if (joliet == 0)
5416 {
5417 return 1;
5418 }
5419
5420 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5421 if (!file)
5422 {
5423 debug("failed to open %s\n", args[0]);
5424 return 1;
5425 }
5426
5427 boot_catlog = ventoy_get_iso_boot_catlog(file);
5428 if (boot_catlog == 0)
5429 {
5430 debug("no bootcatlog found %u\n", boot_catlog);
5431 goto out;
5432 }
5433
5434 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5435 if (loadrba == 0)
5436 {
5437 debug("no bios eltorito rba found %u\n", loadrba);
5438 goto out;
5439 }
5440
5441 grub_file_seek(file, loadrba * 2048);
5442 grub_file_read(file, sector, 512);
5443
5444 info = (boot_info_table *)sector;
5445 if (info->bi_data0 == 0x7c6ceafa &&
5446 info->bi_data1 == 0x90900000 &&
5447 info->bi_PrimaryVolumeDescriptor == 16 &&
5448 info->bi_BootFileLocation == loadrba)
5449 {
5450 debug("bootloader is syslinux, %u.\n", loadrba);
5451 ret = 0;
5452 }
5453
5454 out:
5455
5456 grub_file_close(file);
5457 grub_errno = GRUB_ERR_NONE;
5458 return ret;
5459 }
5460
5461 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5462 {
5463 int n = 0;
5464 ventoy_vlnk_part *node;
5465
5466 (void)ctxt;
5467 (void)argc;
5468 (void)args;
5469
5470 for (node = g_vlnk_part_list; node; node = node->next)
5471 {
5472 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5473 ++n, node->device, node->disksig,
5474 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5475 }
5476
5477 return 0;
5478 }
5479
5480 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5481 {
5482 int len = 0;
5483
5484 (void)ctxt;
5485
5486 if (argc == 1)
5487 {
5488 len = (int)grub_strlen(args[0]);
5489 if (grub_file_is_vlnk_suffix(args[0], len))
5490 {
5491 return 0;
5492 }
5493 }
5494
5495 return 1;
5496 }
5497
5498 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5499 {
5500 int vlnk = 0;
5501 const char *name = NULL;
5502
5503 (void)ctxt;
5504
5505 if (argc == 2)
5506 {
5507 grub_env_unset(args[1]);
5508 name = grub_file_get_vlnk(args[0], &vlnk);
5509 if (vlnk)
5510 {
5511 debug("VLNK SRC: <%s>\n", args[0]);
5512 debug("VLNK DST: <%s>\n", name);
5513 grub_env_set(args[1], name);
5514 return 0;
5515 }
5516 }
5517
5518 return 1;
5519 }
5520
5521 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5522 {
5523 int ret = 1;
5524 int len = 0;
5525 grub_file_t file = NULL;
5526 ventoy_vlnk vlnk;
5527 char dst[512];
5528
5529 (void)ctxt;
5530
5531 if (argc != 1)
5532 {
5533 goto out;
5534 }
5535
5536 len = (int)grub_strlen(args[0]);
5537 if (!grub_file_is_vlnk_suffix(args[0], len))
5538 {
5539 grub_printf("Invalid vlnk suffix\n");
5540 goto out;
5541 }
5542
5543 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5544 if (!file)
5545 {
5546 grub_printf("Failed to open %s\n", args[0]);
5547 goto out;
5548 }
5549
5550 if (file->size != 32768)
5551 {
5552 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5553 goto out;
5554 }
5555
5556 grub_memset(&vlnk, 0, sizeof(vlnk));
5557 grub_file_read(file, &vlnk, sizeof(vlnk));
5558
5559 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5560
5561 out:
5562
5563 grub_refresh();
5564 check_free(file, grub_file_close);
5565 grub_errno = GRUB_ERR_NONE;
5566 return ret;
5567 }
5568
5569 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5570 {
5571 (void)ctxt;
5572 (void)argc;
5573 (void)args;
5574
5575 g_iso_vd_id_publisher[0] = 0;
5576 g_iso_vd_id_prepare[0] = 0;
5577 g_iso_vd_id_application[0] = 0;
5578
5579 return 0;
5580 }
5581
5582 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
5583 {
5584 int ret = 1;
5585 int offset = 318;
5586 grub_file_t file = NULL;
5587
5588 (void)ctxt;
5589 (void)argc;
5590
5591 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5592 if (!file)
5593 {
5594 grub_printf("Failed to open %s\n", args[0]);
5595 goto out;
5596 }
5597
5598 grub_file_seek(file, 16 * 2048 + offset);
5599 grub_file_read(file, g_iso_vd_id_publisher, 128);
5600
5601 offset += 128;
5602 grub_file_seek(file, 16 * 2048 + offset);
5603 grub_file_read(file, g_iso_vd_id_prepare, 128);
5604
5605 offset += 128;
5606 grub_file_seek(file, 16 * 2048 + offset);
5607 grub_file_read(file, g_iso_vd_id_application, 128);
5608
5609 out:
5610
5611 check_free(file, grub_file_close);
5612 grub_errno = GRUB_ERR_NONE;
5613 return ret;
5614 }
5615
5616 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
5617 {
5618 int ret = 1;
5619 char *id = g_iso_vd_id_publisher;
5620
5621 (void)ctxt;
5622 (void)argc;
5623
5624 if (args[0][0] == '1')
5625 {
5626 id = g_iso_vd_id_prepare;
5627 }
5628 else if (args[0][0] == '2')
5629 {
5630 id = g_iso_vd_id_application;
5631 }
5632
5633 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
5634 {
5635 ret = 0;
5636 }
5637
5638 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
5639 {
5640 ret = 0;
5641 }
5642
5643 grub_errno = GRUB_ERR_NONE;
5644 return ret;
5645 }
5646
5647 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
5648 {
5649 (void)ctxt;
5650 (void)argc;
5651
5652 g_ventoy_fn_mutex = 0;
5653 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
5654 {
5655 g_ventoy_fn_mutex = 1;
5656 }
5657
5658 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5659 }
5660
5661 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
5662 {
5663 grub_uint64_t total;
5664 grub_uint64_t org_required;
5665 grub_uint64_t new_required;
5666
5667 (void)ctxt;
5668 (void)argc;
5669 (void)args;
5670
5671 #ifdef GRUB_MACHINE_EFI
5672 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
5673 grub_printf("Total pages: %llu\n", (unsigned long long)total);
5674 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
5675 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
5676 #else
5677 (void)total;
5678 (void)org_required;
5679 (void)new_required;
5680 grub_printf("Non EFI mode!\n");
5681 #endif
5682
5683 grub_refresh();
5684
5685 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5686 }
5687
5688 int ventoy_env_init(void)
5689 {
5690 char buf[64];
5691
5692 grub_env_set("vtdebug_flag", "");
5693
5694 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
5695 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5696 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5697 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
5698
5699 ventoy_filt_register(0, ventoy_wrapper_open);
5700
5701 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
5702 if (g_grub_param)
5703 {
5704 g_grub_param->grub_env_get = grub_env_get;
5705 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5706 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5707 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5708 grub_env_set("env_param", buf);
5709 grub_env_set("ventoy_env_param", buf);
5710
5711 grub_env_export("env_param");
5712 grub_env_export("ventoy_env_param");
5713 }
5714
5715 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5716 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5717
5718 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5719 grub_env_set("vtoy_winpeshl_ini_size", buf);
5720
5721 grub_env_export("vtoy_winpeshl_ini_addr");
5722 grub_env_export("vtoy_winpeshl_ini_size");
5723
5724 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
5725 grub_env_set("vtoy_chain_file_size", buf);
5726 grub_env_export("vtoy_chain_file_size");
5727
5728 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
5729 grub_env_set("vtoy_chain_file_read", buf);
5730 grub_env_export("vtoy_chain_file_read");
5731
5732 return 0;
5733 }
5734
5735
5736
5737 static cmd_para ventoy_cmds[] =
5738 {
5739 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
5740 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
5741 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
5742 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
5743 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
5744 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
5745 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
5746 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5747 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5748 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
5749 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
5750 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
5751 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
5752 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
5753 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
5754 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
5755 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
5756 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
5757 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
5758 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
5759 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
5760 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
5761 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
5762 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
5763 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
5764 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
5765 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
5766
5767 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
5768 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
5769 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
5770 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
5771 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
5772 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
5773 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
5774
5775 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
5776 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
5777 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
5778 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
5779 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
5780 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
5781 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
5782 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
5783 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
5784 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
5785
5786
5787 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
5788 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
5789 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
5790 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
5791 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
5792 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
5793 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
5794 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
5795 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
5796 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
5797 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
5798
5799 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
5800 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
5801 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
5802 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
5803 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
5804 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
5805 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
5806
5807 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5808 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5809 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
5810 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
5811 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
5812 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
5813 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
5814 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
5815 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
5816 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
5817
5818 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
5819 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
5820 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
5821 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
5822 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
5823 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
5824 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
5825 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
5826 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
5827
5828 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
5829 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
5830 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
5831 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
5832
5833
5834 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
5835 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
5836 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
5837
5838 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
5839 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
5840 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
5841
5842
5843 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
5844 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
5845 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
5846 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
5847 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
5848 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
5849 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
5850 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
5851 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
5852 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
5853 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
5854 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
5855 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
5856 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
5857
5858 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
5859 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
5860 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
5861 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
5862 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
5863 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
5864 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
5865 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
5866 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
5867 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
5868 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
5869 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
5870
5871 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
5872 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
5873 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
5874 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
5875 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
5876 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
5877 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
5878 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
5879 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
5880 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
5881 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
5882 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
5883 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
5884 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
5885 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
5886 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
5887 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
5888 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
5889 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
5890 };
5891
5892 int ventoy_register_all_cmd(void)
5893 {
5894 grub_uint32_t i;
5895 cmd_para *cur = NULL;
5896
5897 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5898 {
5899 cur = ventoy_cmds + i;
5900 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
5901 cur->summary, cur->description, cur->parser);
5902 }
5903
5904 return 0;
5905 }
5906
5907 int ventoy_unregister_all_cmd(void)
5908 {
5909 grub_uint32_t i;
5910
5911 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5912 {
5913 grub_unregister_extcmd(ventoy_cmds[i].cmd);
5914 }
5915
5916 return 0;
5917 }
5918
5919