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