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