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