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