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