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