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