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