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