]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
5adcdc65ec99b155834cec12426794fcbc8b1497
[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 *cdprompt = NULL;
2752 grub_uint32_t i;
2753 grub_uint8_t chksum = 0;
2754 grub_disk_t disk;
2755
2756 disk = file->device->disk;
2757 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2758
2759 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2760 param->vtoy_disk_part_id = disk->partition->number + 1;
2761 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2762
2763 pos = grub_strstr(file->name, "/");
2764 if (!pos)
2765 {
2766 pos = file->name;
2767 }
2768
2769 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2770
2771 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2772
2773 param->vtoy_img_size = file->size;
2774
2775 param->vtoy_reserved[0] = g_ventoy_break_level;
2776 param->vtoy_reserved[1] = g_ventoy_debug_level;
2777
2778 param->vtoy_reserved[2] = g_ventoy_chain_type;
2779
2780 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2781 param->vtoy_reserved[4] = 0;
2782 if (g_ventoy_chain_type == 1) /* Windows */
2783 {
2784 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2785 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2786 {
2787 param->vtoy_reserved[4] = 1;
2788 }
2789 }
2790
2791 fs = ventoy_get_env("ventoy_fs_probe");
2792 if (fs && grub_strcmp(fs, "udf") == 0)
2793 {
2794 param->vtoy_reserved[3] = 1;
2795 }
2796
2797 /* calculate checksum */
2798 for (i = 0; i < sizeof(ventoy_os_param); i++)
2799 {
2800 chksum += *((grub_uint8_t *)param + i);
2801 }
2802 param->chksum = (grub_uint8_t)(0x100 - chksum);
2803
2804 return;
2805 }
2806
2807 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2808 {
2809 grub_uint32_t i = 0;
2810 grub_uint64_t total = 0;
2811 grub_uint64_t fileblk = 0;
2812 ventoy_img_chunk *chunk = NULL;
2813
2814 for (i = 0; i < chunklist->cur_chunk; i++)
2815 {
2816 chunk = chunklist->chunk + i;
2817
2818 if (chunk->disk_start_sector <= start)
2819 {
2820 debug("%u disk start invalid %lu\n", i, (ulong)start);
2821 return 1;
2822 }
2823
2824 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2825 }
2826
2827 fileblk = (file->size + 511) / 512;
2828
2829 if (total != fileblk)
2830 {
2831 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
2832 if ((file->size % 512) && (total + 1 == fileblk))
2833 {
2834 debug("maybe img file to be processed.\n");
2835 return 0;
2836 }
2837
2838 return 1;
2839 }
2840
2841 return 0;
2842 }
2843
2844 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2845 {
2846 int fs_type;
2847 int len;
2848 grub_uint32_t i = 0;
2849 grub_uint32_t sector = 0;
2850 grub_uint32_t count = 0;
2851 grub_off_t size = 0;
2852 grub_off_t read = 0;
2853
2854 fs_type = ventoy_get_fs_type(file->fs->name);
2855 if (fs_type == ventoy_fs_exfat)
2856 {
2857 grub_fat_get_file_chunk(start, file, chunklist);
2858 }
2859 else if (fs_type == ventoy_fs_ext)
2860 {
2861 grub_ext_get_file_chunk(start, file, chunklist);
2862 }
2863 else
2864 {
2865 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2866 file->read_hook_data = chunklist;
2867
2868 for (size = file->size; size > 0; size -= read)
2869 {
2870 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2871 grub_file_read(file, NULL, read);
2872 }
2873
2874 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2875 {
2876 chunklist->chunk[i].disk_start_sector += start;
2877 chunklist->chunk[i].disk_end_sector += start;
2878 }
2879
2880 if (ventoy_fs_udf == fs_type)
2881 {
2882 for (i = 0; i < chunklist->cur_chunk; i++)
2883 {
2884 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2885 chunklist->chunk[i].img_start_sector = sector;
2886 chunklist->chunk[i].img_end_sector = sector + count - 1;
2887 sector += count;
2888 }
2889 }
2890 }
2891
2892 len = (int)grub_strlen(file->name);
2893 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2894 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2895 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2896 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2897 {
2898 for (i = 0; i < chunklist->cur_chunk; i++)
2899 {
2900 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2901 if (count < 4)
2902 {
2903 count = 1;
2904 }
2905 else
2906 {
2907 count >>= 2;
2908 }
2909
2910 chunklist->chunk[i].img_start_sector = sector;
2911 chunklist->chunk[i].img_end_sector = sector + count - 1;
2912 sector += count;
2913 }
2914 }
2915
2916 return 0;
2917 }
2918
2919 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2920 {
2921 int rc;
2922 grub_file_t file;
2923 grub_disk_addr_t start;
2924
2925 (void)ctxt;
2926 (void)argc;
2927
2928 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2929 if (!file)
2930 {
2931 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2932 }
2933
2934 g_conf_replace_node = NULL;
2935 g_conf_replace_offset = 0;
2936
2937 if (g_img_chunk_list.chunk)
2938 {
2939 grub_free(g_img_chunk_list.chunk);
2940 }
2941
2942 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2943 {
2944 grub_file_close(file);
2945 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2946 }
2947
2948 /* get image chunk data */
2949 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2950 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2951 if (NULL == g_img_chunk_list.chunk)
2952 {
2953 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2954 }
2955
2956 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2957 g_img_chunk_list.cur_chunk = 0;
2958
2959 start = file->device->disk->partition->start;
2960
2961 ventoy_get_block_list(file, &g_img_chunk_list, start);
2962
2963 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2964 grub_file_close(file);
2965
2966 if (rc)
2967 {
2968 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2969 }
2970
2971 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2972 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
2973 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2974 }
2975
2976 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2977 {
2978 grub_uint64_t offset = 0;
2979 grub_uint32_t align = 0;
2980 grub_file_t file = NULL;
2981 conf_replace *node = NULL;
2982
2983 (void)ctxt;
2984 (void)argc;
2985 (void)args;
2986
2987 debug("select conf replace argc:%d\n", argc);
2988
2989 if (argc < 2)
2990 {
2991 return 0;
2992 }
2993
2994 node = ventoy_plugin_find_conf_replace(args[1]);
2995 if (!node)
2996 {
2997 debug("Conf replace not found for %s\n", args[1]);
2998 goto end;
2999 }
3000
3001 debug("Find conf replace for %s\n", args[1]);
3002
3003 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3004 if (file)
3005 {
3006 offset = grub_iso9660_get_last_file_dirent_pos(file);
3007 grub_file_close(file);
3008 }
3009 else if (node->img > 0)
3010 {
3011 offset = 0;
3012 }
3013 else
3014 {
3015 debug("<(loop)%s> NOT exist\n", node->orgconf);
3016 goto end;
3017 }
3018
3019 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3020 if (!file)
3021 {
3022 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3023 goto end;
3024 }
3025
3026 align = ((int)file->size + 2047) / 2048 * 2048;
3027
3028 if (align > vtoy_max_replace_file_size)
3029 {
3030 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3031 goto end;
3032 }
3033
3034 grub_file_read(file, g_conf_replace_new_buf, file->size);
3035 g_conf_replace_new_len = (int)file->size;
3036 g_conf_replace_new_len_align = align;
3037
3038 g_conf_replace_node = node;
3039 g_conf_replace_offset = offset + 2;
3040
3041 if (node->img > 0)
3042 {
3043 g_grub_param->img_replace.magic = GRUB_IMG_REPLACE_MAGIC;
3044 g_grub_param->img_replace.old_name_cnt = 1;
3045 grub_snprintf(g_grub_param->img_replace.old_file_name[0], 256, "%s", node->orgconf);
3046 }
3047
3048 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
3049
3050 end:
3051 if (file)
3052 {
3053 grub_file_close(file);
3054 }
3055 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3056 }
3057
3058 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3059 {
3060 int i = 0;
3061 int pos = 0;
3062 int defidx = 1;
3063 char *buf = NULL;
3064 char configfile[128];
3065 install_template *node = NULL;
3066
3067 (void)ctxt;
3068 (void)argc;
3069 (void)args;
3070
3071 debug("select auto installation argc:%d\n", argc);
3072
3073 if (argc < 1)
3074 {
3075 return 0;
3076 }
3077
3078 node = ventoy_plugin_find_install_template(args[0]);
3079 if (!node)
3080 {
3081 debug("Auto install template not found for %s\n", args[0]);
3082 return 0;
3083 }
3084
3085 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3086 {
3087 defidx = node->autosel;
3088 if (node->timeout < 0)
3089 {
3090 node->cursel = node->autosel - 1;
3091 debug("Auto install template auto select %d\n", node->autosel);
3092 return 0;
3093 }
3094 }
3095
3096 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3097 if (!buf)
3098 {
3099 return 0;
3100 }
3101
3102 if (node->timeout > 0)
3103 {
3104 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3105 }
3106
3107 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3108 " echo %s\n}\n", "");
3109
3110 for (i = 0; i < node->templatenum; i++)
3111 {
3112 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\"{\n"
3113 " echo \"\"\n}\n",
3114 node->templatepath[i].path);
3115 }
3116
3117 g_ventoy_menu_esc = 1;
3118 g_ventoy_suppress_esc = 1;
3119 g_ventoy_suppress_esc_default = defidx;
3120
3121 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3122 grub_script_execute_sourcecode(configfile);
3123
3124 g_ventoy_menu_esc = 0;
3125 g_ventoy_suppress_esc = 0;
3126 g_ventoy_suppress_esc_default = 1;
3127
3128 grub_free(buf);
3129
3130 node->cursel = g_ventoy_last_entry - 1;
3131
3132 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3133 }
3134
3135 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3136 {
3137 int i = 0;
3138 int pos = 0;
3139 int defidx = 1;
3140 char *buf = NULL;
3141 char configfile[128];
3142 persistence_config *node;
3143
3144 (void)ctxt;
3145 (void)argc;
3146 (void)args;
3147
3148 debug("select persistence argc:%d\n", argc);
3149
3150 if (argc < 1)
3151 {
3152 return 0;
3153 }
3154
3155 node = ventoy_plugin_find_persistent(args[0]);
3156 if (!node)
3157 {
3158 debug("Persistence image not found for %s\n", args[0]);
3159 return 0;
3160 }
3161
3162 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3163 {
3164 defidx = node->autosel;
3165 if (node->timeout < 0)
3166 {
3167 node->cursel = node->autosel - 1;
3168 debug("Persistence image auto select %d\n", node->autosel);
3169 return 0;
3170 }
3171 }
3172
3173 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3174 if (!buf)
3175 {
3176 return 0;
3177 }
3178
3179 if (node->timeout > 0)
3180 {
3181 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3182 }
3183
3184 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3185 " echo %s\n}\n", "");
3186
3187 for (i = 0; i < node->backendnum; i++)
3188 {
3189 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3190 " echo \"\"\n}\n",
3191 node->backendpath[i].path);
3192
3193 }
3194
3195 g_ventoy_menu_esc = 1;
3196 g_ventoy_suppress_esc = 1;
3197 g_ventoy_suppress_esc_default = defidx;
3198
3199 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3200 grub_script_execute_sourcecode(configfile);
3201
3202 g_ventoy_menu_esc = 0;
3203 g_ventoy_suppress_esc = 0;
3204 g_ventoy_suppress_esc_default = 1;
3205
3206 grub_free(buf);
3207
3208 node->cursel = g_ventoy_last_entry - 1;
3209
3210 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3211 }
3212
3213 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3214 {
3215 grub_uint32_t i;
3216 ventoy_img_chunk *cur;
3217
3218 (void)ctxt;
3219 (void)argc;
3220 (void)args;
3221
3222 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3223 {
3224 cur = g_img_chunk_list.chunk + i;
3225 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3226 cur->img_start_sector, cur->img_end_sector,
3227 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3228 );
3229 }
3230
3231 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3232 }
3233
3234 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3235 {
3236 grub_uint32_t i;
3237 grub_file_t file;
3238 ventoy_img_chunk_list chunklist;
3239
3240 (void)ctxt;
3241 (void)argc;
3242
3243 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3244 if (!file)
3245 {
3246 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3247 }
3248
3249 /* get image chunk data */
3250 grub_memset(&chunklist, 0, sizeof(chunklist));
3251 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3252 if (NULL == chunklist.chunk)
3253 {
3254 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3255 }
3256
3257 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3258 chunklist.cur_chunk = 0;
3259
3260 ventoy_get_block_list(file, &chunklist, 0);
3261
3262 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3263 {
3264 grub_printf("########## UNSUPPORTED ###############\n");
3265 }
3266
3267 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3268
3269 for (i = 0; i < chunklist.cur_chunk; i++)
3270 {
3271 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3272 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3273 }
3274
3275 grub_printf("\n==================================\n");
3276
3277 for (i = 0; i < chunklist.cur_chunk; i++)
3278 {
3279 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3280 (ulonglong)chunklist.chunk[i].img_start_sector,
3281 (ulonglong)chunklist.chunk[i].img_end_sector,
3282 (ulonglong)chunklist.chunk[i].disk_start_sector,
3283 (ulonglong)chunklist.chunk[i].disk_end_sector
3284 );
3285 }
3286
3287 grub_free(chunklist.chunk);
3288 grub_file_close(file);
3289
3290 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3291 }
3292
3293 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3294 {
3295 int i;
3296 ventoy_grub_param_file_replace *replace = NULL;
3297
3298 (void)ctxt;
3299 (void)argc;
3300 (void)args;
3301
3302 if (argc >= 2)
3303 {
3304 replace = &(g_grub_param->file_replace);
3305 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3306
3307 replace->old_name_cnt = 0;
3308 for (i = 0; i < 4 && i + 1 < argc; i++)
3309 {
3310 replace->old_name_cnt++;
3311 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3312 }
3313
3314 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3315 }
3316
3317 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3318 }
3319
3320 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3321 {
3322 char buf[32];
3323 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3324
3325 (void)ctxt;
3326
3327 if (argc >= 1)
3328 {
3329 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3330 grub_env_set(args[0], buf);
3331 }
3332
3333 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3334 }
3335
3336 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3337 {
3338 (void)ctxt;
3339 (void)argc;
3340 (void)args;
3341
3342 if (argc == 0)
3343 {
3344 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3345 grub_printf("%s", g_list_script_buf);
3346 }
3347 else
3348 {
3349 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3350 grub_printf("%s", g_tree_script_buf);
3351 }
3352
3353 return 0;
3354 }
3355
3356 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3357 {
3358 img_info *cur = g_ventoy_img_list;
3359
3360 (void)ctxt;
3361 (void)argc;
3362 (void)args;
3363
3364 while (cur)
3365 {
3366 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3367 grub_printf("name:<%s>\n\n", cur->name);
3368 cur = cur->next;
3369 }
3370
3371 return 0;
3372 }
3373
3374 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3375 {
3376 (void)ctxt;
3377 (void)argc;
3378 (void)args;
3379
3380 ventoy_plugin_dump_injection();
3381
3382 return 0;
3383 }
3384
3385 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3386 {
3387 (void)ctxt;
3388 (void)argc;
3389 (void)args;
3390
3391 ventoy_plugin_dump_auto_install();
3392
3393 return 0;
3394 }
3395
3396 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3397 {
3398 (void)ctxt;
3399 (void)argc;
3400 (void)args;
3401
3402 ventoy_plugin_dump_persistence();
3403
3404 return 0;
3405 }
3406
3407 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3408 {
3409 (void)ctxt;
3410 (void)argc;
3411 (void)args;
3412
3413 if (argc != 1)
3414 {
3415 return 1;
3416 }
3417
3418 if (args[0][0] == '0')
3419 {
3420 return g_ventoy_memdisk_mode ? 0 : 1;
3421 }
3422 else if (args[0][0] == '1')
3423 {
3424 return g_ventoy_iso_raw ? 0 : 1;
3425 }
3426 else if (args[0][0] == '2')
3427 {
3428 return g_ventoy_iso_uefi_drv ? 0 : 1;
3429 }
3430 else if (args[0][0] == '3')
3431 {
3432 return g_ventoy_grub2_mode ? 0 : 1;
3433 }
3434 else if (args[0][0] == '4')
3435 {
3436 return g_ventoy_wimboot_mode ? 0 : 1;
3437 }
3438
3439 return 1;
3440 }
3441
3442 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3443 {
3444 static int configfile_mode = 0;
3445 char memfile[128] = {0};
3446
3447 (void)ctxt;
3448 (void)argc;
3449 (void)args;
3450
3451 /*
3452 * args[0]: 0:normal 1:configfile
3453 * args[1]: 0:list_buf 1:tree_buf
3454 */
3455
3456 if (argc != 2)
3457 {
3458 debug("Invalid argc %d\n", argc);
3459 return 0;
3460 }
3461
3462 VTOY_CMD_CHECK(1);
3463
3464 if (args[0][0] == '0')
3465 {
3466 if (args[1][0] == '0')
3467 {
3468 grub_script_execute_sourcecode(g_list_script_buf);
3469 }
3470 else
3471 {
3472 grub_script_execute_sourcecode(g_tree_script_buf);
3473 }
3474 }
3475 else
3476 {
3477 if (configfile_mode)
3478 {
3479 debug("Now already in F3 mode %d\n", configfile_mode);
3480 return 0;
3481 }
3482
3483 if (args[1][0] == '0')
3484 {
3485 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3486 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3487 }
3488 else
3489 {
3490 g_ventoy_last_entry = -1;
3491 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3492 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3493 }
3494
3495 configfile_mode = 1;
3496 grub_script_execute_sourcecode(memfile);
3497 configfile_mode = 0;
3498 }
3499
3500 return 0;
3501 }
3502
3503 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3504 {
3505 grub_file_t file;
3506
3507 (void)ctxt;
3508
3509 if (argc != 1)
3510 {
3511 return 1;
3512 }
3513
3514 g_ventoy_case_insensitive = 1;
3515 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3516 g_ventoy_case_insensitive = 0;
3517
3518 grub_errno = 0;
3519
3520 if (file)
3521 {
3522 grub_file_close(file);
3523 return 0;
3524 }
3525 return 1;
3526 }
3527
3528 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3529 {
3530 int id = 0;
3531 int find = 0;
3532 grub_disk_t disk;
3533 const char *isopath = NULL;
3534 char hdname[32];
3535 ventoy_mbr_head mbr;
3536
3537 (void)ctxt;
3538 (void)argc;
3539
3540 if (argc != 1)
3541 {
3542 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3543 }
3544
3545 isopath = grub_env_get("vtoy_iso_part");
3546 if (!isopath)
3547 {
3548 debug("isopath is null %p\n", isopath);
3549 return 0;
3550 }
3551
3552 debug("isopath is %s\n", isopath);
3553
3554 for (id = 0; id < 30 && (find == 0); id++)
3555 {
3556 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3557 if (grub_strstr(isopath, hdname))
3558 {
3559 debug("skip %s ...\n", hdname);
3560 continue;
3561 }
3562
3563 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3564
3565 disk = grub_disk_open(hdname);
3566 if (!disk)
3567 {
3568 debug("%s not exist\n", hdname);
3569 break;
3570 }
3571
3572 grub_memset(&mbr, 0, sizeof(mbr));
3573 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3574 {
3575 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3576 {
3577 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3578 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3579 {
3580
3581 grub_env_set(args[0], hdname);
3582 find = 1;
3583 }
3584 }
3585 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3586 }
3587 else
3588 {
3589 debug("read %s failed\n", hdname);
3590 }
3591
3592 grub_disk_close(disk);
3593 }
3594
3595 return 0;
3596 }
3597
3598 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3599 {
3600 int len = 1024;
3601 grub_file_t file;
3602 char *buf = NULL;
3603
3604 (void)ctxt;
3605 (void)argc;
3606
3607 if (argc != 2)
3608 {
3609 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3610 }
3611
3612 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3613 if (!file)
3614 {
3615 debug("failed to open file %s\n", args[0]);
3616 return 0;
3617 }
3618
3619 buf = grub_malloc(len);
3620 if (!buf)
3621 {
3622 goto end;
3623 }
3624
3625 buf[len - 1] = 0;
3626 grub_file_read(file, buf, len - 1);
3627
3628 ventoy_get_line(buf);
3629 ventoy_set_env(args[1], buf);
3630
3631 end:
3632
3633 grub_check_free(buf);
3634 grub_file_close(file);
3635
3636 return 0;
3637 }
3638
3639 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3640 {
3641 int *pCnt = (int *)data;
3642
3643 (void)disk;
3644
3645 (*pCnt)++;
3646 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3647 "0 %llu linear /dev/ventoy %llu\n",
3648 (ulonglong)partition->len, (ulonglong)partition->start);
3649
3650 return 0;
3651 }
3652
3653 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3654 {
3655 int cnt = 0;
3656 char *device_name = NULL;
3657 grub_device_t dev = NULL;
3658 char buf[64];
3659
3660 (void)ctxt;
3661
3662 g_part_list_pos = 0;
3663 grub_env_unset("vtoy_img_part_file");
3664
3665 if (argc != 1)
3666 {
3667 return 1;
3668 }
3669
3670 device_name = grub_file_get_device_name(args[0]);
3671 if (!device_name)
3672 {
3673 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3674 goto end;
3675 }
3676
3677 dev = grub_device_open(device_name);
3678 if (!dev)
3679 {
3680 debug("grub_device_open failed, %s\n", device_name);
3681 goto end;
3682 }
3683
3684 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
3685
3686 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3687 grub_env_set("vtoy_img_part_file", buf);
3688
3689 grub_snprintf(buf, sizeof(buf), "%d", cnt);
3690 grub_env_set("vtoy_img_part_cnt", buf);
3691
3692 end:
3693
3694 check_free(device_name, grub_free);
3695 check_free(dev, grub_device_close);
3696
3697 return 0;
3698 }
3699
3700
3701 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3702 {
3703 int rc = 1;
3704 grub_file_t file;
3705 char *buf = NULL;
3706
3707 (void)ctxt;
3708 (void)argc;
3709
3710 if (argc != 2)
3711 {
3712 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3713 }
3714
3715 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3716 if (!file)
3717 {
3718 debug("failed to open file %s\n", args[0]);
3719 return 1;
3720 }
3721
3722 buf = grub_malloc(file->size + 1);
3723 if (!buf)
3724 {
3725 goto end;
3726 }
3727
3728 buf[file->size] = 0;
3729 grub_file_read(file, buf, file->size);
3730
3731 if (grub_strstr(buf, args[1]))
3732 {
3733 rc = 0;
3734 }
3735
3736 end:
3737
3738 grub_check_free(buf);
3739 grub_file_close(file);
3740
3741 return rc;
3742 }
3743
3744 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3745 {
3746 int len;
3747 grub_file_t file;
3748 char buf[64];
3749 grub_uint64_t size;
3750 ventoy_iso9660_vd pvd;
3751
3752 (void)ctxt;
3753 (void)argc;
3754
3755 if (argc != 4)
3756 {
3757 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3758 }
3759
3760 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3761 if (!file)
3762 {
3763 debug("failed to open file %s\n", args[0]);
3764 return 0;
3765 }
3766
3767 grub_file_seek(file, 16 * 2048);
3768 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3769 if (len != sizeof(pvd))
3770 {
3771 debug("failed to read pvd %d\n", len);
3772 goto end;
3773 }
3774
3775 grub_memset(buf, 0, sizeof(buf));
3776 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3777 ventoy_set_env(args[1], buf);
3778
3779 grub_memset(buf, 0, sizeof(buf));
3780 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3781 ventoy_set_env(args[2], buf);
3782
3783 size = pvd.space;
3784 size *= 2048;
3785 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3786 ventoy_set_env(args[3], buf);
3787
3788 end:
3789 grub_file_close(file);
3790
3791 return 0;
3792 }
3793
3794 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3795 {
3796 int len;
3797 grub_file_t file;
3798 char buf[64];
3799
3800 (void)ctxt;
3801 (void)argc;
3802
3803 if (argc != 2)
3804 {
3805 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3806 }
3807
3808 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3809 if (!file)
3810 {
3811 debug("failed to open file %s\n", args[0]);
3812 return 0;
3813 }
3814
3815 grub_memset(buf, 0, sizeof(buf));
3816 grub_file_seek(file, 16 * 2048 + 813);
3817 len = (int)grub_file_read(file, buf, 17);
3818 if (len != 17)
3819 {
3820 debug("failed to read create date %d\n", len);
3821 goto end;
3822 }
3823
3824 ventoy_set_env(args[1], buf);
3825
3826 end:
3827 grub_file_close(file);
3828
3829 return 0;
3830 }
3831
3832 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3833 {
3834 (void)ctxt;
3835 (void)argc;
3836 (void)args;
3837
3838 ventoy_env_hook_root(1);
3839
3840 return 0;
3841 }
3842
3843 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3844 {
3845 (void)ctxt;
3846 (void)argc;
3847 (void)args;
3848
3849 ventoy_env_hook_root(0);
3850
3851 return 0;
3852 }
3853
3854 #ifdef GRUB_MACHINE_EFI
3855 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3856 {
3857 int ret = 1;
3858 grub_uint8_t *var;
3859 grub_size_t size;
3860 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3861
3862 (void)ctxt;
3863 (void)argc;
3864 (void)args;
3865
3866 var = grub_efi_get_variable("SecureBoot", &global, &size);
3867 if (var && *var == 1)
3868 {
3869 return 0;
3870 }
3871
3872 return ret;
3873 }
3874 #else
3875 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3876 {
3877 (void)ctxt;
3878 (void)argc;
3879 (void)args;
3880 return 1;
3881 }
3882 #endif
3883
3884 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3885 {
3886 int i;
3887 int ret = 1;
3888 grub_file_t file;
3889 grub_uint64_t FileSectors = 0;
3890 ventoy_gpt_info *gpt = NULL;
3891 ventoy_part_table *pt = NULL;
3892 grub_uint8_t zeroguid[16] = {0};
3893
3894 (void)ctxt;
3895 (void)argc;
3896
3897 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3898 if (!file)
3899 {
3900 debug("failed to open file %s\n", args[0]);
3901 return 1;
3902 }
3903
3904 if (file->size % 512)
3905 {
3906 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3907 goto out;
3908 }
3909
3910 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3911 if (!gpt)
3912 {
3913 goto out;
3914 }
3915
3916 FileSectors = file->size / 512;
3917
3918 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3919 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3920 {
3921 debug("This is EFI partition table\n");
3922
3923 for (i = 0; i < 128; i++)
3924 {
3925 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3926 {
3927 if (FileSectors < gpt->PartTbl[i].LastLBA)
3928 {
3929 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3930 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3931 goto out;
3932 }
3933 }
3934 }
3935 }
3936 else
3937 {
3938 debug("This is MBR partition table\n");
3939
3940 for (i = 0; i < 4; i++)
3941 {
3942 pt = gpt->MBR.PartTbl + i;
3943 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3944 {
3945 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3946 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3947 (ulonglong)FileSectors);
3948 goto out;
3949 }
3950 }
3951 }
3952
3953 ret = 0;
3954
3955 out:
3956 grub_file_close(file);
3957 grub_check_free(gpt);
3958 grub_errno = GRUB_ERR_NONE;
3959 return ret;
3960 }
3961
3962 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3963 {
3964 int i;
3965 int ret;
3966
3967 (void)ctxt;
3968 (void)argc;
3969 (void)args;
3970
3971 for (i = 0; i < 500; i++)
3972 {
3973 ret = grub_getkey_noblock();
3974 if (ret == GRUB_TERM_NO_KEY)
3975 {
3976 break;
3977 }
3978 }
3979
3980 if (i >= 500)
3981 {
3982 grub_cls();
3983 grub_printf("\n\n Still have key input after clear.\n");
3984 grub_refresh();
3985 grub_sleep(5);
3986 }
3987
3988 return 0;
3989 }
3990
3991 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3992 {
3993 int i;
3994 int buflen;
3995 int datalen;
3996 int loclen;
3997 int img_chunk_num;
3998 int image_sector_size;
3999 char cmd[64];
4000 ventoy_chain_head *chain;
4001 ventoy_img_chunk *chunk;
4002 ventoy_os_param *osparam;
4003 ventoy_image_location *location;
4004 ventoy_image_disk_region *region;
4005 struct grub_acpi_table_header *acpi;
4006
4007 (void)ctxt;
4008
4009 if (argc != 2)
4010 {
4011 return 1;
4012 }
4013
4014 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4015
4016 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4017 if (!chain)
4018 {
4019 return 1;
4020 }
4021
4022 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4023
4024 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4025 {
4026 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4027 return 1;
4028 }
4029
4030 img_chunk_num = chain->img_chunk_num;
4031
4032 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4033 datalen = sizeof(ventoy_os_param) + loclen;
4034
4035 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4036 acpi = grub_zalloc(buflen);
4037 if (!acpi)
4038 {
4039 return 1;
4040 }
4041
4042 /* Step1: Fill acpi table header */
4043 grub_memcpy(acpi->signature, "VTOY", 4);
4044 acpi->length = buflen;
4045 acpi->revision = 1;
4046 grub_memcpy(acpi->oemid, "VENTOY", 6);
4047 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4048 acpi->oemrev = 1;
4049 acpi->creator_id[0] = 1;
4050 acpi->creator_rev = 1;
4051
4052 /* Step2: Fill data */
4053 osparam = (ventoy_os_param *)(acpi + 1);
4054 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4055 osparam->vtoy_img_location_addr = 0;
4056 osparam->vtoy_img_location_len = loclen;
4057 osparam->chksum = 0;
4058 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4059
4060 location = (ventoy_image_location *)(osparam + 1);
4061 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4062 location->image_sector_size = image_sector_size;
4063 location->disk_sector_size = chain->disk_sector_size;
4064 location->region_count = img_chunk_num;
4065
4066 region = location->regions;
4067 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4068 if (512 == image_sector_size)
4069 {
4070 for (i = 0; i < img_chunk_num; i++)
4071 {
4072 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4073 region->image_start_sector = chunk->img_start_sector * 4;
4074 region->disk_start_sector = chunk->disk_start_sector;
4075 region++;
4076 chunk++;
4077 }
4078 }
4079 else
4080 {
4081 for (i = 0; i < img_chunk_num; i++)
4082 {
4083 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4084 region->image_start_sector = chunk->img_start_sector;
4085 region->disk_start_sector = chunk->disk_start_sector;
4086 region++;
4087 chunk++;
4088 }
4089 }
4090
4091 /* Step3: Fill acpi checksum */
4092 acpi->checksum = 0;
4093 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4094
4095 /* load acpi table */
4096 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4097 grub_script_execute_sourcecode(cmd);
4098
4099 grub_free(acpi);
4100
4101 VENTOY_CMD_RETURN(0);
4102 }
4103
4104 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4105 {
4106 (void)ctxt;
4107 (void)argc;
4108 (void)args;
4109
4110 g_ventoy_last_entry_back = g_ventoy_last_entry;
4111 g_ventoy_last_entry = -1;
4112
4113 return 0;
4114 }
4115
4116 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4117 {
4118 (void)ctxt;
4119 (void)argc;
4120 (void)args;
4121
4122 g_ventoy_last_entry = g_ventoy_last_entry_back;
4123
4124 return 0;
4125 }
4126
4127 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4128 {
4129 const char *pos = filename + 1;
4130
4131 if (info->dir)
4132 {
4133 while (*pos)
4134 {
4135 if (*pos == '.')
4136 {
4137 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4138 {
4139 grub_strncpy((char *)data, filename, 128);
4140 return 1;
4141 }
4142 }
4143 pos++;
4144 }
4145 }
4146
4147 return 0;
4148 }
4149
4150 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4151 {
4152 int rc = 1;
4153 char *device_name = NULL;
4154 grub_device_t dev = NULL;
4155 grub_fs_t fs = NULL;
4156 char buf[128] = {0};
4157
4158 (void)ctxt;
4159
4160 if (argc != 3)
4161 {
4162 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4163 return 1;
4164 }
4165
4166 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4167
4168 device_name = grub_file_get_device_name(args[0]);
4169 if (!device_name)
4170 {
4171 debug("grub_file_get_device_name failed, %s\n", args[0]);
4172 goto end;
4173 }
4174
4175 dev = grub_device_open(device_name);
4176 if (!dev)
4177 {
4178 debug("grub_device_open failed, %s\n", device_name);
4179 goto end;
4180 }
4181
4182 fs = grub_fs_probe(dev);
4183 if (!fs)
4184 {
4185 debug("grub_fs_probe failed, %s\n", device_name);
4186 goto end;
4187 }
4188
4189 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4190
4191 if (buf[0])
4192 {
4193 ventoy_set_env(args[2], buf);
4194 }
4195
4196 rc = 0;
4197
4198 end:
4199
4200 check_free(device_name, grub_free);
4201 check_free(dev, grub_device_close);
4202
4203 return rc;
4204 }
4205
4206 int ventoy_load_part_table(const char *diskname)
4207 {
4208 char name[64];
4209 int ret;
4210 grub_disk_t disk;
4211 grub_device_t dev;
4212
4213 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4214 if (!g_ventoy_part_info)
4215 {
4216 return 1;
4217 }
4218
4219 disk = grub_disk_open(diskname);
4220 if (!disk)
4221 {
4222 debug("Failed to open disk %s\n", diskname);
4223 return 1;
4224 }
4225
4226 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4227
4228 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4229 grub_disk_close(disk);
4230
4231 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4232 dev = grub_device_open(name);
4233 if (dev)
4234 {
4235 /* Check for official Ventoy device */
4236 ret = ventoy_check_official_device(dev);
4237 grub_device_close(dev);
4238
4239 if (ret)
4240 {
4241 return 1;
4242 }
4243 }
4244
4245 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4246 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4247
4248 return 0;
4249 }
4250
4251 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4252 {
4253 int ret;
4254
4255 (void)argc;
4256 (void)ctxt;
4257
4258 ret = ventoy_load_part_table(args[0]);
4259 if (ret)
4260 {
4261 grub_exit();
4262 }
4263
4264 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4265 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4266
4267 return 0;
4268 }
4269
4270 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4271 {
4272 int ret = 1;
4273 const char *vcfg = NULL;
4274
4275 (void)argc;
4276 (void)ctxt;
4277
4278 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4279 if (vcfg)
4280 {
4281 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4282 grub_env_set(args[1], vcfg);
4283 ret = 0;
4284 }
4285 else
4286 {
4287 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4288 }
4289
4290 grub_errno = 0;
4291 return ret;
4292 }
4293
4294
4295 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4296 {
4297 int id;
4298 grub_uint8_t zeroguid[16] = {0};
4299
4300 (void)argc;
4301 (void)ctxt;
4302
4303 id = (int)grub_strtoul(args[0], NULL, 10);
4304 grub_errno = 0;
4305
4306 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4307 {
4308 if (id >= 1 && id <= 128)
4309 {
4310 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4311 {
4312 return 0;
4313 }
4314 }
4315 }
4316 else
4317 {
4318 if (id >= 1 && id <= 4)
4319 {
4320 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4321 {
4322 return 0;
4323 }
4324 }
4325 }
4326
4327 return 1;
4328 }
4329
4330 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4331 {
4332 int rc = 1;
4333 char *device_name = NULL;
4334 grub_device_t dev = NULL;
4335 grub_fs_t fs = NULL;
4336 char *label = NULL;
4337
4338 (void)ctxt;
4339
4340 debug("get fs label for %s\n", args[0]);
4341
4342 if (argc != 2)
4343 {
4344 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4345 return 1;
4346 }
4347
4348 device_name = grub_file_get_device_name(args[0]);
4349 if (!device_name)
4350 {
4351 debug("grub_file_get_device_name failed, %s\n", args[0]);
4352 goto end;
4353 }
4354
4355 dev = grub_device_open(device_name);
4356 if (!dev)
4357 {
4358 debug("grub_device_open failed, %s\n", device_name);
4359 goto end;
4360 }
4361
4362 fs = grub_fs_probe(dev);
4363 if (NULL == fs || NULL == fs->fs_label)
4364 {
4365 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4366 goto end;
4367 }
4368
4369 fs->fs_label(dev, &label);
4370 if (label)
4371 {
4372 debug("label=<%s>\n", label);
4373 ventoy_set_env(args[1], label);
4374 grub_free(label);
4375 }
4376
4377 rc = 0;
4378
4379 end:
4380
4381 check_free(device_name, grub_free);
4382 check_free(dev, grub_device_close);
4383
4384 return rc;
4385 }
4386
4387 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4388 {
4389 if (!info->dir)
4390 {
4391 grub_snprintf((char *)data, 256, "%s", filename);
4392 return 1;
4393 }
4394
4395 return 0;
4396 }
4397
4398 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4399 {
4400 if (info->dir && filename && filename[0] != '.')
4401 {
4402 grub_snprintf((char *)data, 256, "%s", filename);
4403 return 1;
4404 }
4405
4406 return 0;
4407 }
4408
4409 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4410 {
4411 int rc = 1;
4412 char *device_name = NULL;
4413 grub_device_t dev = NULL;
4414 grub_fs_t fs = NULL;
4415 char name[256] ={0};
4416
4417 if (argc != 3)
4418 {
4419 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4420 return 1;
4421 }
4422
4423 device_name = grub_file_get_device_name(args[0]);
4424 if (!device_name)
4425 {
4426 debug("grub_file_get_device_name failed, %s\n", args[0]);
4427 goto end;
4428 }
4429
4430 dev = grub_device_open(device_name);
4431 if (!dev)
4432 {
4433 debug("grub_device_open failed, %s\n", device_name);
4434 goto end;
4435 }
4436
4437 fs = grub_fs_probe(dev);
4438 if (!fs)
4439 {
4440 debug("grub_fs_probe failed, %s\n", device_name);
4441 goto end;
4442 }
4443
4444 fs->fs_dir(dev, args[1], hook, name);
4445 if (name[0])
4446 {
4447 ventoy_set_env(args[2], name);
4448 }
4449
4450 rc = 0;
4451
4452 end:
4453
4454 check_free(device_name, grub_free);
4455 check_free(dev, grub_device_close);
4456
4457 return rc;
4458 }
4459
4460 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4461 {
4462 (void)ctxt;
4463 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4464 }
4465
4466 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4467 {
4468 (void)ctxt;
4469 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4470 }
4471
4472 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4473 {
4474 char c;
4475 char *pos = NULL;
4476 char *end = NULL;
4477
4478 (void)ctxt;
4479
4480 if (argc != 2)
4481 {
4482 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4483 return 1;
4484 }
4485
4486 for (pos = args[0]; *pos; pos++)
4487 {
4488 if (*pos == '.')
4489 {
4490 end = pos;
4491 }
4492 }
4493
4494 if (end)
4495 {
4496 c = *end;
4497 *end = 0;
4498 }
4499
4500 grub_env_set(args[1], args[0]);
4501
4502 if (end)
4503 {
4504 *end = c;
4505 }
4506
4507 return 0;
4508 }
4509
4510 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4511 {
4512 int i;
4513 int len;
4514 const char *buf;
4515
4516 (void)ctxt;
4517
4518 if (argc != 2)
4519 {
4520 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4521 return 1;
4522 }
4523
4524 buf = args[0];
4525 len = (int)grub_strlen(buf);
4526 for (i = len; i > 0; i--)
4527 {
4528 if (buf[i - 1] == '/')
4529 {
4530 grub_env_set(args[1], buf + i);
4531 return 0;
4532 }
4533 }
4534
4535 grub_env_set(args[1], buf);
4536
4537 return 0;
4538 }
4539
4540 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4541 {
4542 struct grub_video_mode_info info;
4543 char buf[32];
4544
4545 (void)ctxt;
4546 (void)argc;
4547 (void)args;
4548
4549 if (!g_video_mode_list)
4550 {
4551 ventoy_enum_video_mode();
4552 }
4553
4554 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4555 {
4556 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4557 }
4558 else
4559 {
4560 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4561 }
4562
4563 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4564
4565 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4566 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4567
4568 VENTOY_CMD_RETURN(0);
4569 }
4570
4571 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4572 {
4573 struct grub_video_mode_info info;
4574 char buf[32];
4575
4576 (void)ctxt;
4577 (void)argc;
4578 (void)args;
4579
4580 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4581 {
4582 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4583 }
4584 else
4585 {
4586 grub_snprintf(buf, sizeof(buf), "0x0x0");
4587 }
4588
4589 grub_env_set(args[0], buf);
4590
4591 VENTOY_CMD_RETURN(0);
4592 }
4593
4594 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4595 {
4596 int id;
4597 char buf[32];
4598
4599 (void)ctxt;
4600 (void)argc;
4601
4602 if (!g_video_mode_list)
4603 {
4604 return 0;
4605 }
4606
4607 id = (int)grub_strtoul(args[0], NULL, 10);
4608 if (id < g_video_mode_num)
4609 {
4610 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4611 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4612 }
4613
4614 grub_env_set(args[1], buf);
4615
4616 VENTOY_CMD_RETURN(0);
4617 }
4618
4619 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4620 {
4621 grub_uint32_t i;
4622 grub_uint32_t loadsector = 0;
4623 grub_file_t file;
4624 char value[32];
4625 grub_uint32_t boot_catlog = 0;
4626 grub_uint8_t buf[512];
4627
4628 (void)ctxt;
4629
4630 if (argc != 2)
4631 {
4632 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4633 return 1;
4634 }
4635
4636 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4637 if (!file)
4638 {
4639 debug("failed to open %s\n", args[0]);
4640 return 1;
4641 }
4642
4643 boot_catlog = ventoy_get_iso_boot_catlog(file);
4644 if (boot_catlog == 0)
4645 {
4646 debug("No bootcatlog found\n");
4647 grub_file_close(file);
4648 return 1;
4649 }
4650
4651 grub_memset(buf, 0, sizeof(buf));
4652 grub_file_seek(file, boot_catlog * 2048);
4653 grub_file_read(file, buf, sizeof(buf));
4654 grub_file_close(file);
4655
4656 for (i = 0; i < sizeof(buf); i += 32)
4657 {
4658 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4659 {
4660 if (buf[i + 32] == 0x88)
4661 {
4662 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4663 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4664 break;
4665 }
4666 }
4667 }
4668
4669 if (loadsector == 0)
4670 {
4671 debug("No EFI eltorito info found\n");
4672 return 1;
4673 }
4674
4675 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4676 grub_env_set(args[1], value);
4677 VENTOY_CMD_RETURN(0);
4678 }
4679
4680 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4681 {
4682 int curpos;
4683 int printlen;
4684 grub_size_t len;
4685 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4686
4687 if (pfsdir->initrd[0])
4688 {
4689 return 1;
4690 }
4691
4692 curpos = pfsdir->curpos;
4693 len = grub_strlen(filename);
4694
4695 if (info->dir)
4696 {
4697 if ((len == 1 && filename[0] == '.') ||
4698 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4699 {
4700 return 0;
4701 }
4702
4703 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4704 pfsdir->dircnt++;
4705
4706 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4707 pfsdir->curpos = curpos + printlen;
4708 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4709 pfsdir->curpos = curpos;
4710 pfsdir->fullpath[curpos] = 0;
4711 }
4712 else
4713 {
4714 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4715 pfsdir->filecnt++;
4716
4717 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4718 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4719 {
4720 if (info->size > 32 * VTOY_SIZE_1MB)
4721 {
4722 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4723 return 1;
4724 }
4725 }
4726 }
4727
4728 return 0;
4729 }
4730
4731 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4732 {
4733 int i;
4734 char *pos = NULL;
4735 char *device_name = NULL;
4736 grub_device_t dev = NULL;
4737 grub_fs_t fs = NULL;
4738 replace_fs_dir *pfsdir = NULL;
4739
4740 (void)ctxt;
4741
4742 if (argc != 2)
4743 {
4744 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4745 return 1;
4746 }
4747
4748 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4749 if (!pfsdir)
4750 {
4751 return 1;
4752 }
4753
4754 device_name = grub_file_get_device_name(args[0]);
4755 if (!device_name)
4756 {
4757 goto fail;
4758 }
4759
4760 dev = grub_device_open(device_name);
4761 if (!dev)
4762 {
4763 goto fail;
4764 }
4765
4766 fs = grub_fs_probe(dev);
4767 if (!fs)
4768 {
4769 goto fail;
4770 }
4771
4772 pfsdir->dev = dev;
4773 pfsdir->fs = fs;
4774 pfsdir->curpos = 1;
4775 pfsdir->fullpath[0] = '/';
4776 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4777
4778 if (pfsdir->initrd[0])
4779 {
4780 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4781
4782 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4783 {
4784 if (pfsdir->initrd[i] == '/')
4785 {
4786 pfsdir->initrd[i] = '\\';
4787 }
4788 }
4789
4790 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4791 grub_env_set(args[1], pos);
4792 }
4793 else
4794 {
4795 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4796 }
4797
4798 fail:
4799
4800 grub_check_free(pfsdir);
4801 grub_check_free(device_name);
4802 check_free(dev, grub_device_close);
4803
4804 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4805 }
4806
4807 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4808 {
4809 const char *pager = NULL;
4810
4811 (void)ctxt;
4812 (void)argc;
4813 (void)args;
4814
4815 pager = grub_env_get("pager");
4816 if (NULL == pager)
4817 {
4818 g_pager_flag = 1;
4819 grub_env_set("pager", "1");
4820 }
4821 else if (pager[0] == '1')
4822 {
4823 g_pager_flag = 0;
4824 }
4825 else
4826 {
4827 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
4828 g_pager_flag = 2;
4829 grub_env_set("pager", "1");
4830 }
4831
4832 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4833 }
4834
4835 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4836 {
4837 (void)ctxt;
4838 (void)argc;
4839 (void)args;
4840
4841 if (g_pager_flag == 1)
4842 {
4843 grub_env_unset("pager");
4844 }
4845 else if (g_pager_flag == 2)
4846 {
4847 grub_env_set("pager", g_old_pager);
4848 }
4849
4850 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4851 }
4852
4853 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4854 {
4855 if (g_json_case_mis_path[0])
4856 {
4857 return 1;
4858 }
4859
4860 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
4861 {
4862 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
4863 return 1;
4864 }
4865 return 0;
4866 }
4867
4868 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4869 {
4870 char path[16];
4871 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
4872
4873 if (g_json_case_mis_path[0])
4874 {
4875 return 1;
4876 }
4877
4878 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
4879 {
4880 if (grub_strcasecmp(filename, "ventoy") == 0)
4881 {
4882 grub_snprintf(path, sizeof(path), "/%s", filename);
4883 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
4884 if (g_json_case_mis_path[0])
4885 {
4886 return 1;
4887 }
4888 }
4889 }
4890
4891 return 0;
4892 }
4893
4894 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
4895 {
4896 int fstype = 0;
4897 char *device_name = NULL;
4898 grub_device_t dev = NULL;
4899 grub_fs_t fs = NULL;
4900 chk_case_fs_dir fs_dir;
4901
4902 (void)ctxt;
4903 (void)argc;
4904 (void)args;
4905
4906 device_name = grub_file_get_device_name(args[0]);
4907 if (!device_name)
4908 {
4909 goto out;
4910 }
4911
4912 dev = grub_device_open(device_name);
4913 if (!dev)
4914 {
4915 goto out;
4916 }
4917
4918 fs = grub_fs_probe(dev);
4919 if (!fs)
4920 {
4921 goto out;
4922 }
4923
4924 fstype = ventoy_get_fs_type(fs->name);
4925 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
4926 {
4927 goto out;
4928 }
4929
4930 g_json_case_mis_path[0] = 0;
4931 fs_dir.dev = dev;
4932 fs_dir.fs = fs;
4933 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
4934
4935 if (g_json_case_mis_path[0])
4936 {
4937 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
4938 }
4939
4940 out:
4941
4942 grub_check_free(device_name);
4943 check_free(dev, grub_device_close);
4944
4945 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4946 }
4947
4948 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
4949 {
4950 grub_disk_t disk;
4951 grub_partition_t part;
4952 char priority_str[3]; /* Maximum value 15 */
4953
4954 (void)ctxt;
4955
4956 if (argc < 2 || argc > 3)
4957 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4958 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
4959
4960 /* Open the disk if it exists */
4961 disk = grub_disk_open (args[0]);
4962 if (!disk)
4963 {
4964 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4965 "Not a disk");
4966 }
4967
4968 part = grub_partition_probe (disk, args[1]);
4969 if (!part)
4970 {
4971 grub_disk_close (disk);
4972 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4973 "No such partition");
4974 }
4975
4976 if (grub_strcmp (part->partmap->name, "gpt"))
4977 {
4978 grub_disk_close (disk);
4979 return grub_error (GRUB_ERR_BAD_PART_TABLE,
4980 "Not a GPT partition");
4981 }
4982
4983 grub_snprintf (priority_str, sizeof(priority_str), "%u",
4984 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
4985
4986 if (argc == 3)
4987 {
4988 grub_env_set (args[2], priority_str);
4989 grub_env_export (args[2]);
4990 }
4991 else
4992 {
4993 grub_printf ("Priority is %s\n", priority_str);
4994 }
4995
4996 grub_disk_close (disk);
4997 return GRUB_ERR_NONE;
4998 }
4999
5000
5001 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5002 {
5003 int ret = 1;
5004 int joliet = 0;
5005 grub_file_t file = NULL;
5006 grub_uint32_t loadrba = 0;
5007 grub_uint32_t boot_catlog = 0;
5008 grub_uint8_t sector[512];
5009 boot_info_table *info = NULL;
5010
5011 (void)ctxt;
5012 (void)argc;
5013
5014 /* This also trigger a iso9660 fs parse */
5015 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5016 {
5017 return 0;
5018 }
5019
5020 joliet = grub_iso9660_is_joliet();
5021 if (joliet == 0)
5022 {
5023 return 1;
5024 }
5025
5026 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5027 if (!file)
5028 {
5029 debug("failed to open %s\n", args[0]);
5030 return 1;
5031 }
5032
5033 boot_catlog = ventoy_get_iso_boot_catlog(file);
5034 if (boot_catlog == 0)
5035 {
5036 debug("no bootcatlog found %u\n", boot_catlog);
5037 goto out;
5038 }
5039
5040 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5041 if (loadrba == 0)
5042 {
5043 debug("no bios eltorito rba found %u\n", loadrba);
5044 goto out;
5045 }
5046
5047 grub_file_seek(file, loadrba * 2048);
5048 grub_file_read(file, sector, 512);
5049
5050 info = (boot_info_table *)sector;
5051 if (info->bi_data0 == 0x7c6ceafa &&
5052 info->bi_data1 == 0x90900000 &&
5053 info->bi_PrimaryVolumeDescriptor == 16 &&
5054 info->bi_BootFileLocation == loadrba)
5055 {
5056 debug("bootloader is syslinux, %u.\n", loadrba);
5057 ret = 0;
5058 }
5059
5060 out:
5061
5062 grub_file_close(file);
5063 grub_errno = GRUB_ERR_NONE;
5064 return ret;
5065 }
5066
5067 int ventoy_env_init(void)
5068 {
5069 char buf[64];
5070
5071 grub_env_set("vtdebug_flag", "");
5072
5073 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
5074 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5075 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5076 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
5077
5078 ventoy_filt_register(0, ventoy_wrapper_open);
5079
5080 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
5081 if (g_grub_param)
5082 {
5083 g_grub_param->grub_env_get = grub_env_get;
5084 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5085 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5086 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5087 grub_env_set("env_param", buf);
5088 grub_env_set("ventoy_env_param", buf);
5089
5090 grub_env_export("env_param");
5091 grub_env_export("ventoy_env_param");
5092 }
5093
5094 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5095 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5096
5097 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5098 grub_env_set("vtoy_winpeshl_ini_size", buf);
5099
5100 grub_env_export("vtoy_winpeshl_ini_addr");
5101 grub_env_export("vtoy_winpeshl_ini_size");
5102
5103 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
5104 grub_env_set("vtoy_chain_file_size", buf);
5105 grub_env_export("vtoy_chain_file_size");
5106
5107 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
5108 grub_env_set("vtoy_chain_file_read", buf);
5109 grub_env_export("vtoy_chain_file_read");
5110
5111 return 0;
5112 }
5113
5114
5115
5116 static cmd_para ventoy_cmds[] =
5117 {
5118 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
5119 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
5120 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
5121 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
5122 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
5123 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5124 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5125 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
5126 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
5127 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
5128 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
5129 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
5130 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
5131 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
5132 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
5133 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
5134 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
5135 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
5136 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
5137 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
5138 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
5139 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
5140 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
5141 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
5142 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
5143
5144 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
5145 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
5146 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
5147 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
5148 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
5149 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
5150 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
5151
5152 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
5153 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
5154 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
5155 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
5156 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
5157 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
5158 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
5159 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
5160 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
5161 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
5162
5163
5164 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
5165 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
5166 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
5167 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
5168 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
5169 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
5170 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
5171 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
5172 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
5173 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
5174 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
5175
5176 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
5177 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
5178 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
5179 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
5180 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
5181 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
5182 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
5183
5184 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5185 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5186 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
5187 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
5188 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
5189 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
5190 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
5191 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
5192 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
5193 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
5194
5195 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
5196 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
5197 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
5198 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
5199 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
5200 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
5201 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
5202 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
5203 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
5204
5205 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
5206 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
5207 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
5208 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
5209
5210
5211 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
5212 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
5213 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
5214
5215 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
5216 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
5217 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
5218
5219
5220 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
5221 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
5222 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
5223 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
5224 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
5225 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
5226 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
5227 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
5228 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
5229 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
5230 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
5231 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
5232
5233 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
5234 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
5235 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
5236 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
5237 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
5238 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
5239 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
5240 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
5241 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
5242 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
5243 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
5244 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
5245
5246 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
5247 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
5248 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
5249 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
5250 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
5251 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
5252 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
5253 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
5254 };
5255
5256 int ventoy_register_all_cmd(void)
5257 {
5258 grub_uint32_t i;
5259 cmd_para *cur = NULL;
5260
5261 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5262 {
5263 cur = ventoy_cmds + i;
5264 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
5265 cur->summary, cur->description, cur->parser);
5266 }
5267
5268 return 0;
5269 }
5270
5271 int ventoy_unregister_all_cmd(void)
5272 {
5273 grub_uint32_t i;
5274
5275 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5276 {
5277 grub_unregister_extcmd(ventoy_cmds[i].cmd);
5278 }
5279
5280 return 0;
5281 }
5282
5283