]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
002a47baa06e5daf00a4c4165b8e4ae92e0a42cb
[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 const char *g_menu_class[img_type_max] =
152 {
153 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
154 };
155
156 const char *g_menu_prefix[img_type_max] =
157 {
158 "iso", "wim", "efi", "img", "vhd", "vtoy"
159 };
160
161 static int g_vtoy_secondary_need_recover = 0;
162
163 static int g_vtoy_load_prompt = 0;
164 static char g_vtoy_prompt_msg[64];
165
166 static char g_json_case_mis_path[32];
167
168 static ventoy_vlnk_part *g_vlnk_part_list = NULL;
169
170 int ventoy_get_fs_type(const char *fs)
171 {
172 if (NULL == fs)
173 {
174 return ventoy_fs_max;
175 }
176 else if (grub_strncmp(fs, "exfat", 5) == 0)
177 {
178 return ventoy_fs_exfat;
179 }
180 else if (grub_strncmp(fs, "ntfs", 4) == 0)
181 {
182 return ventoy_fs_ntfs;
183 }
184 else if (grub_strncmp(fs, "ext", 3) == 0)
185 {
186 return ventoy_fs_ext;
187 }
188 else if (grub_strncmp(fs, "xfs", 3) == 0)
189 {
190 return ventoy_fs_xfs;
191 }
192 else if (grub_strncmp(fs, "udf", 3) == 0)
193 {
194 return ventoy_fs_udf;
195 }
196 else if (grub_strncmp(fs, "fat", 3) == 0)
197 {
198 return ventoy_fs_fat;
199 }
200
201 return ventoy_fs_max;
202 }
203
204 static int ventoy_string_check(const char *str, grub_char_check_func check)
205 {
206 if (!str)
207 {
208 return 0;
209 }
210
211 for ( ; *str; str++)
212 {
213 if (!check(*str))
214 {
215 return 0;
216 }
217 }
218
219 return 1;
220 }
221
222
223 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
224 {
225 grub_memcpy(buf, (char *)file->data + file->offset, len);
226 return len;
227 }
228
229 static int ventoy_control_get_flag(const char *key)
230 {
231 const char *val = ventoy_get_env(key);
232
233 if (val && val[0] == '1' && val[1] == 0)
234 {
235 return 1;
236 }
237 return 0;
238 }
239
240 static grub_err_t ventoy_fs_close(grub_file_t file)
241 {
242 grub_file_close(g_old_file);
243 grub_free(file->data);
244
245 file->device = 0;
246 file->name = 0;
247
248 return 0;
249 }
250
251 static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg)
252 {
253 int i;
254
255 (void)hook_arg;
256
257 if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
258 {
259 return 0;
260 }
261
262 for (i = 0; i < g_video_mode_num; i++)
263 {
264 if (g_video_mode_list[i].width == info->width &&
265 g_video_mode_list[i].height == info->height &&
266 g_video_mode_list[i].bpp == info->bpp)
267 {
268 return 0;
269 }
270 }
271
272 g_video_mode_list[g_video_mode_num].width = info->width;
273 g_video_mode_list[g_video_mode_num].height = info->height;
274 g_video_mode_list[g_video_mode_num].bpp = info->bpp;
275 g_video_mode_num++;
276
277 if (g_video_mode_num == g_video_mode_max)
278 {
279 g_video_mode_max *= 2;
280 g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode));
281 }
282
283 return 0;
284 }
285
286 static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2)
287 {
288 if (v1->bpp == v2->bpp)
289 {
290 if (v1->width == v2->width)
291 {
292 if (v1->height == v2->height)
293 {
294 return 0;
295 }
296 else
297 {
298 return (v1->height < v2->height) ? -1 : 1;
299 }
300 }
301 else
302 {
303 return (v1->width < v2->width) ? -1 : 1;
304 }
305 }
306 else
307 {
308 return (v1->bpp < v2->bpp) ? -1 : 1;
309 }
310 }
311
312 static int ventoy_enum_video_mode(void)
313 {
314 int i, j;
315 grub_video_adapter_t adapter;
316 grub_video_driver_id_t id;
317 ventoy_video_mode mode;
318
319 g_video_mode_num = 0;
320 g_video_mode_max = 1024;
321 g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max);
322 if (!g_video_mode_list)
323 {
324 return 0;
325 }
326
327 #ifdef GRUB_MACHINE_PCBIOS
328 grub_dl_load ("vbe");
329 #endif
330
331 id = grub_video_get_driver_id ();
332
333 FOR_VIDEO_ADAPTERS (adapter)
334 {
335 if (!adapter->iterate ||
336 (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE ||
337 adapter->init() != GRUB_ERR_NONE)))
338 {
339 continue;
340 }
341
342 adapter->iterate(ventoy_video_hook, NULL);
343
344 if (adapter->id != id)
345 {
346 adapter->fini();
347 }
348 }
349
350 /* sort video mode */
351 for (i = 0; i < g_video_mode_num; i++)
352 for (j = i + 1; j < g_video_mode_num; j++)
353 {
354 if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0)
355 {
356 grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode));
357 grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode));
358 grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode));
359 }
360 }
361
362 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
363 }
364
365 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
366 {
367 int len;
368 grub_file_t file;
369 static struct grub_fs vtoy_fs =
370 {
371 .name = "vtoy",
372 .fs_dir = 0,
373 .fs_open = 0,
374 .fs_read = ventoy_fs_read,
375 .fs_close = ventoy_fs_close,
376 .fs_label = 0,
377 .next = 0
378 };
379
380 if (type != 52)
381 {
382 return rawFile;
383 }
384
385 file = (grub_file_t)grub_zalloc(sizeof (*file));
386 if (!file)
387 {
388 return 0;
389 }
390
391 file->data = grub_malloc(rawFile->size + 4096);
392 if (!file->data)
393 {
394 return 0;
395 }
396
397 grub_file_read(rawFile, file->data, rawFile->size);
398 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
399
400 g_old_file = rawFile;
401
402 file->size = rawFile->size + len;
403 file->device = rawFile->device;
404 file->fs = &vtoy_fs;
405 file->not_easily_seekable = 1;
406
407 return file;
408 }
409
410 static int ventoy_check_decimal_var(const char *name, long *value)
411 {
412 const char *value_str = NULL;
413
414 value_str = grub_env_get(name);
415 if (NULL == value_str)
416 {
417 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
418 }
419
420 if (!ventoy_is_decimal(value_str))
421 {
422 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
423 }
424
425 *value = grub_strtol(value_str, NULL, 10);
426
427 return GRUB_ERR_NONE;
428 }
429
430 grub_uint64_t ventoy_get_vtoy_partsize(int part)
431 {
432 grub_uint64_t sectors;
433
434 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
435 {
436 sectors = g_ventoy_part_info->PartTbl[part].LastLBA + 1 - g_ventoy_part_info->PartTbl[part].StartLBA;
437 }
438 else
439 {
440 sectors = g_ventoy_part_info->MBR.PartTbl[part].SectorCount;
441 }
442
443 return sectors * 512;
444 }
445
446 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
447 {
448 int len;
449 grub_file_t file;
450 char exec[128];
451 char *data = NULL;
452 grub_uint32_t offset;
453
454 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
455 if (file == NULL)
456 {
457 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
458 return 1;
459 }
460
461 len = (int)file->size;
462
463 data = (char *)grub_malloc(file->size);
464 if (!data)
465 {
466 return 1;
467 }
468
469 grub_file_read(file, data, file->size);
470 grub_file_close(file);
471
472 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
473 grub_script_execute_sourcecode(exec);
474
475 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
476 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
477 grub_file_close(file);
478
479 grub_script_execute_sourcecode("loopback -d efiboot");
480
481 *buf = data;
482 *datalen = len;
483 *direntoff = offset + 2;
484
485 return 0;
486 }
487
488 static int ventoy_set_check_result(int ret, const char *msg)
489 {
490 char buf[32];
491
492 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
493 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
494 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
495
496 if (ret)
497 {
498 grub_printf(VTOY_WARNING"\n");
499 grub_printf(VTOY_WARNING"\n");
500 grub_printf(VTOY_WARNING"\n\n\n");
501
502 grub_printf("This is NOT a standard Ventoy device and is NOT supported (%d).\n", ret);
503 grub_printf("Error message: <%s>\n\n", msg);
504 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
505
506 grub_printf("\n\nWill exit after 10 seconds ...... ");
507 grub_refresh();
508 grub_sleep(10);
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 name[32];
1040 char value[32];
1041 char *buf = NULL;
1042 char *data = NULL;
1043 ventoy_iso9660_override *dirent;
1044
1045 (void)ctxt;
1046
1047 if (argc != 2)
1048 {
1049 return 1;
1050 }
1051
1052 totlen = sizeof(ventoy_chain_head);
1053
1054 if (ventoy_load_efiboot_template(&buf, &len, &offset))
1055 {
1056 debug("failed to load efiboot template %d\n", len);
1057 return 1;
1058 }
1059
1060 totlen += len;
1061
1062 debug("efiboot template len:%d offset:%d\n", len, offset);
1063
1064 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
1065 if (file == NULL)
1066 {
1067 debug("failed to open file <%s>\n", args[0]);
1068 return 1;
1069 }
1070
1071 if (grub_strncmp(args[0], g_iso_path, grub_strlen(g_iso_path)))
1072 {
1073 file->vlnk = 1;
1074 }
1075
1076 totlen += ventoy_align_2k(file->size);
1077
1078 dirent = (ventoy_iso9660_override *)(buf + offset);
1079 dirent->first_sector = len / 2048;
1080 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
1081 dirent->size = (grub_uint32_t)file->size;
1082 dirent->size_be = grub_swap_bytes32(dirent->size);
1083
1084 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
1085
1086 #ifdef GRUB_MACHINE_EFI
1087 data = (char *)grub_efi_allocate_iso_buf(totlen);
1088 #else
1089 data = (char *)grub_malloc(totlen);
1090 #endif
1091
1092 ventoy_fill_os_param(file, (ventoy_os_param *)data);
1093
1094 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
1095 grub_check_free(buf);
1096
1097 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
1098 grub_file_close(file);
1099
1100 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1101 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
1102 grub_env_set(name, value);
1103
1104 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1105 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
1106 grub_env_set(name, value);
1107
1108 return 0;
1109 }
1110
1111 grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args)
1112 {
1113 (void)ctxt;
1114 (void)argc;
1115 (void)args;
1116
1117 g_vtoy_load_prompt = 0;
1118 grub_memset(g_vtoy_prompt_msg, 0, sizeof(g_vtoy_prompt_msg));
1119
1120 if (argc == 2 && args[0][0] == '1')
1121 {
1122 g_vtoy_load_prompt = 1;
1123 grub_snprintf(g_vtoy_prompt_msg, sizeof(g_vtoy_prompt_msg), "%s", args[1]);
1124 }
1125
1126 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1127 }
1128
1129 int ventoy_need_prompt_load_file(void)
1130 {
1131 return g_vtoy_load_prompt;
1132 }
1133
1134 grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size)
1135 {
1136 grub_uint64_t ro = 0;
1137 grub_uint64_t div = 0;
1138 grub_ssize_t left = size;
1139 char *cur = (char *)buf;
1140
1141 grub_printf("\r%s 1%% ", g_vtoy_prompt_msg);
1142 grub_refresh();
1143
1144 while (left >= VTOY_SIZE_2MB)
1145 {
1146 grub_file_read(file, cur, VTOY_SIZE_2MB);
1147 cur += VTOY_SIZE_2MB;
1148 left -= VTOY_SIZE_2MB;
1149
1150 div = grub_divmod64((grub_uint64_t)((size - left) * 100), (grub_uint64_t)size, &ro);
1151 if (div < 1)
1152 {
1153 div = 1;
1154 }
1155 grub_printf("\r%s %d%% ", g_vtoy_prompt_msg, (int)div);
1156 grub_refresh();
1157 }
1158
1159 if (left > 0)
1160 {
1161 grub_file_read(file, cur, left);
1162 }
1163
1164 grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg);
1165 grub_refresh();
1166
1167 return size;
1168 }
1169
1170 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
1171 {
1172 int rc = 1;
1173 char name[32];
1174 char value[32];
1175 char *buf = NULL;
1176 grub_file_t file;
1177 enum grub_file_type type;
1178
1179 (void)ctxt;
1180 (void)argc;
1181 (void)args;
1182
1183 if (argc != 3)
1184 {
1185 return rc;
1186 }
1187
1188 if (grub_strcmp(args[0], "nodecompress") == 0)
1189 {
1190 type = VENTOY_FILE_TYPE;
1191 }
1192 else
1193 {
1194 type = GRUB_FILE_TYPE_LINUX_INITRD;
1195 }
1196
1197 file = ventoy_grub_file_open(type, "%s", args[1]);
1198 if (file == NULL)
1199 {
1200 debug("failed to open file <%s>\n", args[1]);
1201 return 1;
1202 }
1203
1204 #ifdef GRUB_MACHINE_EFI
1205 buf = (char *)grub_efi_allocate_chain_buf(file->size);
1206 #else
1207 buf = (char *)grub_malloc(file->size);
1208 #endif
1209
1210 if (!buf)
1211 {
1212 grub_file_close(file);
1213 return 1;
1214 }
1215
1216 if (g_vtoy_load_prompt)
1217 {
1218 ventoy_load_file_with_prompt(file, buf, file->size);
1219 }
1220 else
1221 {
1222 grub_file_read(file, buf, file->size);
1223 }
1224
1225 grub_snprintf(name, sizeof(name), "%s_addr", args[2]);
1226 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1227 grub_env_set(name, value);
1228
1229 grub_snprintf(name, sizeof(name), "%s_size", args[2]);
1230 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1231 grub_env_set(name, value);
1232
1233 grub_file_close(file);
1234 rc = 0;
1235
1236 return rc;
1237 }
1238
1239 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
1240 {
1241 int rc = 1;
1242 int headlen;
1243 char name[32];
1244 char value[32];
1245 char *buf = NULL;
1246 grub_file_t file;
1247
1248 (void)ctxt;
1249 (void)argc;
1250 (void)args;
1251
1252 if (argc != 2)
1253 {
1254 return rc;
1255 }
1256
1257 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1258 if (file == NULL)
1259 {
1260 debug("failed to open file <%s> for udf check\n", args[0]);
1261 return 1;
1262 }
1263
1264 headlen = sizeof(ventoy_chain_head);
1265
1266 #ifdef GRUB_MACHINE_EFI
1267 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
1268 #else
1269 buf = (char *)grub_malloc(headlen + file->size);
1270 #endif
1271
1272 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
1273
1274 grub_file_read(file, buf + headlen, file->size);
1275
1276 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1277 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1278 grub_env_set(name, value);
1279
1280 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1281 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1282 grub_env_set(name, value);
1283
1284 grub_file_close(file);
1285 rc = 0;
1286
1287 return rc;
1288 }
1289
1290 static grub_err_t ventoy_cmd_iso9660_is_joliet(grub_extcmd_context_t ctxt, int argc, char **args)
1291 {
1292 (void)ctxt;
1293 (void)argc;
1294 (void)args;
1295
1296 if (grub_iso9660_is_joliet())
1297 {
1298 debug("This time has joliet process\n");
1299 return 0;
1300 }
1301 else
1302 {
1303 return 1;
1304 }
1305 }
1306
1307 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
1308 {
1309 (void)ctxt;
1310
1311 if (argc != 1)
1312 {
1313 return 1;
1314 }
1315
1316 if (args[0][0] == '1')
1317 {
1318 grub_iso9660_set_nojoliet(1);
1319 }
1320 else
1321 {
1322 grub_iso9660_set_nojoliet(0);
1323 }
1324
1325 return 0;
1326 }
1327
1328 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
1329 {
1330 int i;
1331 int rc = 1;
1332 grub_file_t file;
1333 grub_uint8_t buf[32];
1334
1335 (void)ctxt;
1336 (void)argc;
1337 (void)args;
1338
1339 if (argc != 1)
1340 {
1341 return rc;
1342 }
1343
1344 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1345 if (file == NULL)
1346 {
1347 debug("failed to open file <%s> for udf check\n", args[0]);
1348 return 1;
1349 }
1350
1351 for (i = 16; i < 32; i++)
1352 {
1353 grub_file_seek(file, i * 2048);
1354 grub_file_read(file, buf, sizeof(buf));
1355 if (buf[0] == 255)
1356 {
1357 break;
1358 }
1359 }
1360
1361 i++;
1362 grub_file_seek(file, i * 2048);
1363 grub_file_read(file, buf, sizeof(buf));
1364
1365 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
1366 {
1367 i++;
1368 grub_file_seek(file, i * 2048);
1369 grub_file_read(file, buf, sizeof(buf));
1370
1371 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
1372 grub_memcmp(buf + 1, "NSR03", 5) == 0)
1373 {
1374 rc = 0;
1375 }
1376 }
1377
1378 grub_file_close(file);
1379
1380 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
1381
1382 return rc;
1383 }
1384
1385 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
1386 {
1387 long value_long1 = 0;
1388 long value_long2 = 0;
1389
1390 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
1391 {
1392 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
1393 }
1394
1395 value_long1 = grub_strtol(args[0], NULL, 10);
1396 value_long2 = grub_strtol(args[2], NULL, 10);
1397
1398 if (0 == grub_strcmp(args[1], "eq"))
1399 {
1400 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1401 }
1402 else if (0 == grub_strcmp(args[1], "ne"))
1403 {
1404 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1405 }
1406 else if (0 == grub_strcmp(args[1], "gt"))
1407 {
1408 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1409 }
1410 else if (0 == grub_strcmp(args[1], "lt"))
1411 {
1412 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1413 }
1414 else if (0 == grub_strcmp(args[1], "ge"))
1415 {
1416 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1417 }
1418 else if (0 == grub_strcmp(args[1], "le"))
1419 {
1420 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1421 }
1422 else
1423 {
1424 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
1425 }
1426
1427 return grub_errno;
1428 }
1429
1430 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
1431 {
1432 char *pos = NULL;
1433 char buf[128] = {0};
1434
1435 if (argc != 2)
1436 {
1437 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
1438 }
1439
1440 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
1441 pos = grub_strstr(buf, ",");
1442 if (pos)
1443 {
1444 *pos = 0;
1445 }
1446
1447 grub_env_set(args[1], buf);
1448
1449 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1450 }
1451
1452 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
1453 {
1454 int i;
1455 char buf[256];
1456 grub_disk_t disk;
1457 char *pos = NULL;
1458 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
1459
1460 (void)ctxt;
1461
1462 if (argc != 1)
1463 {
1464 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
1465 }
1466
1467 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
1468 {
1469 grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]);
1470 if (0 == grub_script_execute_sourcecode(buf))
1471 {
1472 debug("file %s exist, ventoy_compatible YES\n", buf);
1473 grub_env_set("ventoy_compatible", "YES");
1474 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1475 }
1476 else
1477 {
1478 debug("file %s NOT exist\n", buf);
1479 }
1480 }
1481
1482 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
1483 pos = grub_strstr(buf, ")");
1484 if (pos)
1485 {
1486 *pos = 0;
1487 }
1488
1489 disk = grub_disk_open(buf);
1490 if (disk)
1491 {
1492 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
1493 grub_disk_close(disk);
1494
1495 g_img_swap_tmp_buf[703] = 0;
1496 for (i = 318; i < 703; i++)
1497 {
1498 if (g_img_swap_tmp_buf[i] == 'V' &&
1499 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
1500 {
1501 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
1502 grub_env_set("ventoy_compatible", "YES");
1503 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1504 }
1505 }
1506 }
1507 else
1508 {
1509 debug("failed to open disk <%s>\n", buf);
1510 }
1511
1512 grub_env_set("ventoy_compatible", "NO");
1513 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1514 }
1515
1516 int ventoy_cmp_img(img_info *img1, img_info *img2)
1517 {
1518 char *s1, *s2;
1519 int c1 = 0;
1520 int c2 = 0;
1521
1522 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1523 {
1524 return (img1->plugin_list_index - img2->plugin_list_index);
1525 }
1526
1527 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1528 {
1529 c1 = *s1;
1530 c2 = *s2;
1531
1532 if (0 == g_sort_case_sensitive)
1533 {
1534 if (grub_islower(c1))
1535 {
1536 c1 = c1 - 'a' + 'A';
1537 }
1538
1539 if (grub_islower(c2))
1540 {
1541 c2 = c2 - 'a' + 'A';
1542 }
1543 }
1544
1545 if (c1 != c2)
1546 {
1547 break;
1548 }
1549 }
1550
1551 return (c1 - c2);
1552 }
1553
1554 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1555 {
1556 char *s1, *s2;
1557 int c1 = 0;
1558 int c2 = 0;
1559
1560 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1561 {
1562 return (node1->plugin_list_index - node2->plugin_list_index);
1563 }
1564
1565 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1566 {
1567 c1 = *s1;
1568 c2 = *s2;
1569
1570 if (0 == g_sort_case_sensitive)
1571 {
1572 if (grub_islower(c1))
1573 {
1574 c1 = c1 - 'a' + 'A';
1575 }
1576
1577 if (grub_islower(c2))
1578 {
1579 c2 = c2 - 'a' + 'A';
1580 }
1581 }
1582
1583 if (c1 != c2)
1584 {
1585 break;
1586 }
1587 }
1588
1589 return (c1 - c2);
1590 }
1591
1592 void ventoy_swap_img(img_info *img1, img_info *img2)
1593 {
1594 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1595
1596 grub_memcpy(img1, img2, sizeof(img_info));
1597 img1->next = g_img_swap_tmp.next;
1598 img1->prev = g_img_swap_tmp.prev;
1599
1600 g_img_swap_tmp.next = img2->next;
1601 g_img_swap_tmp.prev = img2->prev;
1602 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1603 }
1604
1605 int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1606 {
1607 (void)namelen;
1608
1609 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1610 {
1611 return 0;
1612 }
1613
1614 return 1;
1615 }
1616
1617 static int ventoy_vlnk_iterate_partition(struct grub_disk *disk, const grub_partition_t partition, void *data)
1618 {
1619 ventoy_vlnk_part *node = NULL;
1620 grub_uint32_t SelfSig;
1621 grub_uint32_t *pSig = (grub_uint32_t *)data;
1622
1623 /* skip Ventoy partition 1/2 */
1624 grub_memcpy(&SelfSig, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
1625 if (partition->number < 2 && SelfSig == *pSig)
1626 {
1627 return 0;
1628 }
1629
1630 node = grub_zalloc(sizeof(ventoy_vlnk_part));
1631 if (node)
1632 {
1633 node->disksig = *pSig;
1634 node->partoffset = (partition->start << GRUB_DISK_SECTOR_BITS);
1635 grub_snprintf(node->disk, sizeof(node->disk) - 1, "%s", disk->name);
1636 grub_snprintf(node->device, sizeof(node->device) - 1, "%s,%d", disk->name, partition->number + 1);
1637
1638 node->next = g_vlnk_part_list;
1639 g_vlnk_part_list = node;
1640 }
1641
1642 return 0;
1643 }
1644
1645 static int ventoy_vlnk_iterate_disk(const char *name, void *data)
1646 {
1647 grub_disk_t disk;
1648 grub_uint32_t sig;
1649
1650 (void)data;
1651
1652 disk = grub_disk_open(name);
1653 if (disk)
1654 {
1655 grub_disk_read(disk, 0, 0x1b8, 4, &sig);
1656 grub_partition_iterate(disk, ventoy_vlnk_iterate_partition, &sig);
1657 grub_disk_close(disk);
1658 }
1659
1660 return 0;
1661 }
1662
1663 static int ventoy_vlnk_probe_fs(ventoy_vlnk_part *cur)
1664 {
1665 const char *fs[ventoy_fs_max + 1] =
1666 {
1667 "exfat", "ntfs", "ext2", "xfs", "udf", "fat", NULL
1668 };
1669
1670 if (!cur->dev)
1671 {
1672 cur->dev = grub_device_open(cur->device);
1673 }
1674
1675 if (cur->dev)
1676 {
1677 cur->fs = grub_fs_list_probe(cur->dev, fs);
1678 }
1679
1680 return 0;
1681 }
1682
1683 static int ventoy_check_vlnk_data(ventoy_vlnk *vlnk, int print, char *dst, int size)
1684 {
1685 int diskfind = 0;
1686 int partfind = 0;
1687 int filefind = 0;
1688 char *disk, *device;
1689 grub_uint32_t readcrc, calccrc;
1690 ventoy_vlnk_part *cur;
1691 grub_fs_t fs = NULL;
1692
1693 if (grub_memcmp(&(vlnk->guid), &g_ventoy_guid, sizeof(ventoy_guid)))
1694 {
1695 if (print)
1696 {
1697 grub_printf("VLNK invalid guid\n");
1698 grub_refresh();
1699 }
1700 return 1;
1701 }
1702
1703 readcrc = vlnk->crc32;
1704 vlnk->crc32 = 0;
1705 calccrc = grub_getcrc32c(0, vlnk, sizeof(ventoy_vlnk));
1706 if (readcrc != calccrc)
1707 {
1708 if (print)
1709 {
1710 grub_printf("VLNK invalid crc 0x%08x 0x%08x\n", calccrc, readcrc);
1711 grub_refresh();
1712 }
1713 return 1;
1714 }
1715
1716 if (!g_vlnk_part_list)
1717 {
1718 grub_disk_dev_iterate(ventoy_vlnk_iterate_disk, NULL);
1719 }
1720
1721 for (cur = g_vlnk_part_list; cur && filefind == 0; cur = cur->next)
1722 {
1723 if (cur->disksig == vlnk->disk_signature)
1724 {
1725 diskfind = 1;
1726 disk = cur->disk;
1727 if (cur->partoffset == vlnk->part_offset)
1728 {
1729 partfind = 1;
1730 device = cur->device;
1731
1732 if (cur->probe == 0)
1733 {
1734 cur->probe = 1;
1735 ventoy_vlnk_probe_fs(cur);
1736 }
1737
1738 if (!fs)
1739 {
1740 fs = cur->fs;
1741 }
1742
1743 if (cur->fs)
1744 {
1745 struct grub_file file;
1746
1747 grub_memset(&file, 0, sizeof(file));
1748 file.device = cur->dev;
1749 if (cur->fs->fs_open(&file, vlnk->filepath) == GRUB_ERR_NONE)
1750 {
1751 filefind = 1;
1752 cur->fs->fs_close(&file);
1753 grub_snprintf(dst, size - 1, "(%s)%s", cur->device, vlnk->filepath);
1754 }
1755 }
1756 }
1757 }
1758 }
1759
1760 if (print)
1761 {
1762 grub_printf("\n==== VLNK Information ====\n"
1763 "Disk Signature: %08x\n"
1764 "Partition Offset: %llu\n"
1765 "File Path: <%s>\n\n",
1766 vlnk->disk_signature, (ulonglong)vlnk->part_offset, vlnk->filepath);
1767
1768 if (diskfind)
1769 {
1770 grub_printf("Disk Find: [ YES ] [ %s ]\n", disk);
1771 }
1772 else
1773 {
1774 grub_printf("Disk Find: [ NO ]\n");
1775 }
1776
1777 if (partfind)
1778 {
1779 grub_printf("Part Find: [ YES ] [ %s ] [ %s ]\n", device, fs ? fs->name : "N/A");
1780 }
1781 else
1782 {
1783 grub_printf("Part Find: [ NO ]\n");
1784 }
1785 grub_printf("File Find: [ %s ]\n", filefind ? "YES" : "NO");
1786 if (filefind)
1787 {
1788 grub_printf("VLNK File: <%s>\n", dst);
1789 }
1790
1791 grub_printf("\n");
1792 grub_refresh();
1793 }
1794
1795 return (1 - filefind);
1796 }
1797
1798 int ventoy_add_vlnk_file(char *dir, const char *name)
1799 {
1800 int rc = 1;
1801 char src[512];
1802 char dst[512];
1803 grub_file_t file = NULL;
1804 ventoy_vlnk vlnk;
1805
1806 if (!dir)
1807 {
1808 grub_snprintf(src, sizeof(src), "%s%s", g_iso_path, name);
1809 }
1810 else if (dir[0] == '/')
1811 {
1812 grub_snprintf(src, sizeof(src), "%s%s%s", g_iso_path, dir, name);
1813 }
1814 else
1815 {
1816 grub_snprintf(src, sizeof(src), "%s/%s%s", g_iso_path, dir, name);
1817 }
1818
1819 file = grub_file_open(src, VENTOY_FILE_TYPE);
1820 if (!file)
1821 {
1822 return 1;
1823 }
1824
1825 grub_memset(&vlnk, 0, sizeof(vlnk));
1826 grub_file_read(file, &vlnk, sizeof(vlnk));
1827 grub_file_close(file);
1828
1829 if (ventoy_check_vlnk_data(&vlnk, 0, dst, sizeof(dst)) == 0)
1830 {
1831 rc = grub_file_add_vlnk(src, dst);
1832 }
1833
1834 return rc;
1835 }
1836
1837 static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1838 {
1839 //int i = 0;
1840 int type = 0;
1841 int ignore = 0;
1842 int index = 0;
1843 int vlnk = 0;
1844 grub_size_t len;
1845 img_info *img;
1846 img_info *tail;
1847 const menu_tip *tip;
1848 img_iterator_node *tmp;
1849 img_iterator_node *new_node;
1850 img_iterator_node *node = (img_iterator_node *)data;
1851
1852 if (g_enumerate_time_checked == 0)
1853 {
1854 g_enumerate_finish_time_ms = grub_get_time_ms();
1855 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1856 {
1857 grub_cls();
1858 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1859 grub_refresh();
1860 g_enumerate_time_checked = 1;
1861 }
1862 }
1863
1864 len = grub_strlen(filename);
1865
1866 if (info->dir)
1867 {
1868 if (node->level + 1 > g_img_max_search_level)
1869 {
1870 return 0;
1871 }
1872
1873 if ((len == 1 && filename[0] == '.') ||
1874 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1875 {
1876 return 0;
1877 }
1878
1879 if (!ventoy_img_name_valid(filename, len))
1880 {
1881 return 0;
1882 }
1883
1884 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1885 {
1886 return 0;
1887 }
1888
1889 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1890 {
1891 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1892 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1893 if (index == 0)
1894 {
1895 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1896 return 0;
1897 }
1898 }
1899
1900 new_node = grub_zalloc(sizeof(img_iterator_node));
1901 if (new_node)
1902 {
1903 new_node->level = node->level + 1;
1904 new_node->plugin_list_index = index;
1905 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1906
1907 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1908 if (ignore)
1909 {
1910 debug("Directory %s ignored...\n", new_node->dir);
1911 grub_free(new_node);
1912 return 0;
1913 }
1914
1915 new_node->tail = node->tail;
1916
1917 new_node->parent = node;
1918 if (!node->firstchild)
1919 {
1920 node->firstchild = new_node;
1921 }
1922
1923 if (g_img_iterator_tail)
1924 {
1925 g_img_iterator_tail->next = new_node;
1926 g_img_iterator_tail = new_node;
1927 }
1928 else
1929 {
1930 g_img_iterator_head.next = new_node;
1931 g_img_iterator_tail = new_node;
1932 }
1933 }
1934 }
1935 else
1936 {
1937 debug("Find a file %s\n", filename);
1938 if (len < 4)
1939 {
1940 return 0;
1941 }
1942
1943 if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso"))
1944 {
1945 type = img_type_iso;
1946 }
1947 else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1948 {
1949 type = img_type_wim;
1950 }
1951 else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1952 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1953 {
1954 type = img_type_vhd;
1955 }
1956 #ifdef GRUB_MACHINE_EFI
1957 else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi"))
1958 {
1959 type = img_type_efi;
1960 }
1961 #endif
1962 else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img"))
1963 {
1964 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1965 {
1966 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1967 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1968 {
1969 return 0;
1970 }
1971 }
1972 type = img_type_img;
1973 }
1974 else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1975 {
1976 type = img_type_vtoy;
1977 }
1978 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1979 {
1980 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1981 {
1982 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1983 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1984 }
1985 return 0;
1986 }
1987 else
1988 {
1989 return 0;
1990 }
1991
1992 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1993 {
1994 return 0;
1995 }
1996
1997 if (g_plugin_image_list)
1998 {
1999 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
2000 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
2001 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
2002 {
2003 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
2004 return 0;
2005 }
2006 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
2007 {
2008 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index);
2009 return 0;
2010 }
2011 }
2012
2013 if (info->size == VTOY_FILT_MIN_FILE_SIZE || info->size == 0)
2014 {
2015 if (grub_file_is_vlnk_suffix(filename, len))
2016 {
2017 vlnk = 1;
2018 if (ventoy_add_vlnk_file(node->dir, filename) != 0)
2019 {
2020 return 0;
2021 }
2022 }
2023 }
2024
2025 img = grub_zalloc(sizeof(img_info));
2026 if (img)
2027 {
2028 img->type = type;
2029 img->plugin_list_index = index;
2030 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
2031
2032 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
2033
2034 img->size = info->size;
2035 if (vlnk || 0 == img->size)
2036 {
2037 if (node->dir[0] == '/')
2038 {
2039 img->size = ventoy_grub_get_file_size("%s%s%s", g_iso_path, node->dir, filename);
2040 }
2041 else
2042 {
2043 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
2044 }
2045 }
2046
2047 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
2048 {
2049 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
2050 grub_free(img);
2051 return 0;
2052 }
2053
2054 if (g_ventoy_img_list)
2055 {
2056 tail = *(node->tail);
2057 img->prev = tail;
2058 tail->next = img;
2059 }
2060 else
2061 {
2062 g_ventoy_img_list = img;
2063 }
2064
2065 img->id = g_ventoy_img_count;
2066 img->parent = node;
2067 if (node && NULL == node->firstiso)
2068 {
2069 node->firstiso = img;
2070 }
2071
2072 node->isocnt++;
2073 tmp = node->parent;
2074 while (tmp)
2075 {
2076 tmp->isocnt++;
2077 tmp = tmp->parent;
2078 }
2079
2080 *((img_info **)(node->tail)) = img;
2081 g_ventoy_img_count++;
2082
2083 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
2084
2085 tip = ventoy_plugin_get_menu_tip(vtoy_tip_image_file, img->path);
2086 if (tip)
2087 {
2088 img->tip1 = tip->tip1;
2089 img->tip2 = tip->tip2;
2090 }
2091
2092 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path);
2093 if (!img->class)
2094 {
2095 img->class = g_menu_class[type];
2096 }
2097 img->menu_prefix = g_menu_prefix[type];
2098
2099 if (img_type_iso == type)
2100 {
2101 if (ventoy_plugin_check_memdisk(img->path))
2102 {
2103 img->menu_prefix = "miso";
2104 }
2105 }
2106
2107 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
2108 }
2109 }
2110
2111 return 0;
2112 }
2113
2114 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
2115 {
2116 int len = GRUB_UINT_MAX;
2117 const char *value = NULL;
2118 char name[32] = {0};
2119 char plat[32] = {0};
2120 char guidstr[32] = {0};
2121 ventoy_guid guid = VENTOY_GUID;
2122 const char *fmt1 = NULL;
2123 const char *fmt2 = NULL;
2124 const char *fmt3 = NULL;
2125 grub_uint32_t *puint = (grub_uint32_t *)name;
2126 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
2127 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
2128 const char fmtcode[]={
2129 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
2130 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
2131 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
2132 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
2133 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
2134 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
2135 };
2136
2137 grub_memset(name, 0, sizeof(name));
2138 puint[0] = grub_swap_bytes32(0x56454e54);
2139 puint[3] = grub_swap_bytes32(0x4f4e0000);
2140 puint[2] = grub_swap_bytes32(0x45525349);
2141 puint[1] = grub_swap_bytes32(0x4f595f56);
2142 value = ventoy_get_env(name);
2143
2144 grub_memset(name, 0, sizeof(name));
2145 puint[1] = grub_swap_bytes32(0x5f544f50);
2146 puint[0] = grub_swap_bytes32(0x56544c45);
2147 fmt1 = ventoy_get_env(name);
2148 if (!fmt1)
2149 {
2150 fmt1 = fmtdata;
2151 }
2152
2153 grub_memset(name, 0, sizeof(name));
2154 puint[1] = grub_swap_bytes32(0x5f4c4654);
2155 puint[0] = grub_swap_bytes32(0x56544c45);
2156 fmt2 = ventoy_get_env(name);
2157
2158 grub_memset(name, 0, sizeof(name));
2159 puint[1] = grub_swap_bytes32(0x5f434c52);
2160 puint[0] = grub_swap_bytes32(0x56544c45);
2161 fmt3 = ventoy_get_env(name);
2162
2163 grub_memcpy(guidstr, &guid, sizeof(guid));
2164
2165 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
2166
2167 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
2168 #pragma GCC diagnostic push
2169 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
2170 len = grub_snprintf(buffer, buflen, fmtcode,
2171 fmt1 ? fmt1 : fmtdata,
2172 fmt2 ? fmt2 : fmtdata + 4,
2173 value ? value : "", plat, guidstr,
2174 fmt3 ? fmt3 : fmtdata + 6);
2175 #pragma GCC diagnostic pop
2176
2177 grub_memset(name, 0, sizeof(name));
2178 puint[0] = grub_swap_bytes32(0x76746f79);
2179 puint[2] = grub_swap_bytes32(0x656e7365);
2180 puint[1] = grub_swap_bytes32(0x5f6c6963);
2181 ventoy_set_env(name, guidstr);
2182
2183 return len;
2184 }
2185
2186 static int
2187 ventoy_password_get (char buf[], unsigned buf_size)
2188 {
2189 unsigned i, cur_len = 0;
2190 int key;
2191 struct grub_term_coordinate *pos = grub_term_save_pos ();
2192
2193 while (1)
2194 {
2195 key = grub_getkey ();
2196 if (key == '\n' || key == '\r')
2197 break;
2198
2199 if (key == GRUB_TERM_ESC)
2200 {
2201 cur_len = 0;
2202 break;
2203 }
2204
2205 if (key == '\b')
2206 {
2207 if (cur_len)
2208 {
2209 grub_term_restore_pos (pos);
2210 for (i = 0; i < cur_len; i++)
2211 grub_xputs (" ");
2212 grub_term_restore_pos (pos);
2213 cur_len--;
2214 for (i = 0; i < cur_len; i++)
2215 grub_xputs ("*");
2216 grub_refresh ();
2217 }
2218 continue;
2219 }
2220
2221 if (!grub_isprint (key))
2222 continue;
2223
2224 if (cur_len + 2 < buf_size)
2225 buf[cur_len++] = key;
2226 grub_xputs ("*");
2227 grub_refresh ();
2228 }
2229
2230 grub_memset (buf + cur_len, 0, buf_size - cur_len);
2231
2232 grub_xputs ("\n");
2233 grub_refresh ();
2234 grub_free (pos);
2235
2236 return (key != GRUB_TERM_ESC);
2237 }
2238
2239 int ventoy_check_password(const vtoy_password *pwd, int retry)
2240 {
2241 int offset;
2242 char input[256];
2243 grub_uint8_t md5[16];
2244
2245 while (retry--)
2246 {
2247 grub_memset(input, 0, sizeof(input));
2248
2249 grub_printf("Enter password: ");
2250 grub_refresh();
2251
2252 if (pwd->type == VTOY_PASSWORD_TXT)
2253 {
2254 ventoy_password_get(input, 128);
2255 if (grub_strcmp(pwd->text, input) == 0)
2256 {
2257 return 0;
2258 }
2259 }
2260 else if (pwd->type == VTOY_PASSWORD_MD5)
2261 {
2262 ventoy_password_get(input, 128);
2263 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2264 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2265 {
2266 return 0;
2267 }
2268 }
2269 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
2270 {
2271 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
2272 ventoy_password_get(input + offset, 128);
2273
2274 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2275 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2276 {
2277 return 0;
2278 }
2279 }
2280
2281 grub_printf("Invalid password!\n\n");
2282 grub_refresh();
2283 }
2284
2285 return 1;
2286 }
2287
2288 static img_info * ventoy_get_min_iso(img_iterator_node *node)
2289 {
2290 img_info *minimg = NULL;
2291 img_info *img = (img_info *)(node->firstiso);
2292
2293 while (img && (img_iterator_node *)(img->parent) == node)
2294 {
2295 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
2296 {
2297 minimg = img;
2298 }
2299 img = img->next;
2300 }
2301
2302 if (minimg)
2303 {
2304 minimg->select = 1;
2305 }
2306
2307 return minimg;
2308 }
2309
2310 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
2311 {
2312 img_iterator_node *Minchild = NULL;
2313 img_iterator_node *child = node->firstchild;
2314
2315 while (child && child->parent == node)
2316 {
2317 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
2318 {
2319 Minchild = child;
2320 }
2321 child = child->next;
2322 }
2323
2324 if (Minchild)
2325 {
2326 Minchild->select = 1;
2327 }
2328
2329 return Minchild;
2330 }
2331
2332 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
2333 {
2334 int offset = 1;
2335 img_info *img = NULL;
2336 const char *dir_class = NULL;
2337 const char *dir_alias = NULL;
2338 img_iterator_node *child = NULL;
2339 const menu_tip *tip = NULL;
2340
2341 if (node->isocnt == 0 || node->done == 1)
2342 {
2343 return 0;
2344 }
2345
2346 if (node->parent && node->parent->dirlen < node->dirlen)
2347 {
2348 offset = node->parent->dirlen;
2349 }
2350
2351 if (node == &g_img_iterator_head)
2352 {
2353 if (g_default_menu_mode == 0)
2354 {
2355 if (g_tree_view_menu_style == 0)
2356 {
2357 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2358 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2359 " echo 'return ...' \n"
2360 "}\n", "<--");
2361 }
2362 else
2363 {
2364 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2365 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2366 " echo 'return ...' \n"
2367 "}\n");
2368 }
2369 }
2370
2371 g_tree_script_pre = g_tree_script_pos;
2372 }
2373 else
2374 {
2375 node->dir[node->dirlen - 1] = 0;
2376 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2377 if (!dir_class)
2378 {
2379 dir_class = "vtoydir";
2380 }
2381
2382 tip = ventoy_plugin_get_menu_tip(vtoy_tip_directory, node->dir);
2383
2384 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2385 if (dir_alias)
2386 {
2387 if (g_tree_view_menu_style == 0)
2388 {
2389 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2390 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2391 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2392 }
2393 else
2394 {
2395 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2396 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2397 dir_alias, dir_class, node->dir + offset, tip);
2398 }
2399 }
2400 else
2401 {
2402 dir_alias = node->dir + offset;
2403
2404 if (g_tree_view_menu_style == 0)
2405 {
2406 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2407 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2408 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2409 }
2410 else
2411 {
2412 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2413 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2414 dir_alias, dir_class, node->dir + offset, tip);
2415 }
2416 }
2417
2418 if (g_tree_view_menu_style == 0)
2419 {
2420 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2421 "menuentry \"%-10s [%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2422 " echo 'return ...' \n"
2423 "}\n", "<--", node->dir);
2424 }
2425 else
2426 {
2427 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2428 "menuentry \"[%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2429 " echo 'return ...' \n"
2430 "}\n", node->dir);
2431 }
2432 }
2433
2434 while ((child = ventoy_get_min_child(node)) != NULL)
2435 {
2436 ventoy_dynamic_tree_menu(child);
2437 }
2438
2439 while ((img = ventoy_get_min_iso(node)) != NULL)
2440 {
2441 if (g_tree_view_menu_style == 0)
2442 {
2443 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2444 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2445 " %s_%s \n"
2446 "}\n",
2447 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2448 img->unsupport ? "[***********] " : "",
2449 img->alias ? img->alias : img->name, img->class, img,
2450 img->menu_prefix,
2451 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2452 }
2453 else
2454 {
2455 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2456 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2457 " %s_%s \n"
2458 "}\n",
2459 img->unsupport ? "[***********] " : "",
2460 img->alias ? img->alias : img->name, img->class, img,
2461 img->menu_prefix,
2462 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2463 }
2464 }
2465
2466 if (node != &g_img_iterator_head)
2467 {
2468 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "}\n");
2469 }
2470
2471 node->done = 1;
2472 return 0;
2473 }
2474
2475 static int ventoy_set_default_menu(void)
2476 {
2477 int img_len = 0;
2478 char *pos = NULL;
2479 char *end = NULL;
2480 char *def = NULL;
2481 const char *strdata = NULL;
2482 img_info *cur = NULL;
2483 img_info *default_node = NULL;
2484 const char *default_image = NULL;
2485
2486 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2487 if (default_image && default_image[0] == '/')
2488 {
2489 img_len = grub_strlen(default_image);
2490
2491 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2492 {
2493 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2494 {
2495 default_node = cur;
2496 break;
2497 }
2498 }
2499
2500 if (!default_node)
2501 {
2502 return 1;
2503 }
2504
2505 if (0 == g_default_menu_mode)
2506 {
2507 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2508 }
2509 else
2510 {
2511 def = grub_strdup(default_image);
2512 if (!def)
2513 {
2514 return 1;
2515 }
2516
2517 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2518
2519 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2520 if (strdata && strdata[0] == '/')
2521 {
2522 pos = def + grub_strlen(strdata);
2523 if (*pos == '/')
2524 {
2525 pos++;
2526 }
2527 }
2528 else
2529 {
2530 pos = def + 1;
2531 }
2532
2533 while ((end = grub_strchr(pos, '/')) != NULL)
2534 {
2535 *end = 0;
2536 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2537 pos = end + 1;
2538 }
2539
2540 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2541 grub_free(def);
2542 }
2543 }
2544
2545 return 0;
2546 }
2547
2548 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2549 {
2550 img_info *next = NULL;
2551 img_info *cur = g_ventoy_img_list;
2552
2553 (void)ctxt;
2554 (void)argc;
2555 (void)args;
2556
2557 while (cur)
2558 {
2559 next = cur->next;
2560 grub_free(cur);
2561 cur = next;
2562 }
2563
2564 g_ventoy_img_list = NULL;
2565 g_ventoy_img_count = 0;
2566
2567 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2568 }
2569
2570 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2571 {
2572 long img_id = 0;
2573 img_info *cur = g_ventoy_img_list;
2574
2575 (void)ctxt;
2576
2577 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2578 {
2579 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2580 }
2581
2582 img_id = grub_strtol(args[0], NULL, 10);
2583 if (img_id >= g_ventoy_img_count)
2584 {
2585 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2586 }
2587
2588 debug("Find image %ld name \n", img_id);
2589
2590 while (cur && img_id > 0)
2591 {
2592 img_id--;
2593 cur = cur->next;
2594 }
2595
2596 if (!cur)
2597 {
2598 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2599 }
2600
2601 debug("image name is %s\n", cur->name);
2602
2603 grub_env_set(args[1], cur->name);
2604
2605 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2606 }
2607
2608 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2609 {
2610 int len = 0;
2611 char id[32] = {0};
2612 img_info *cur = g_ventoy_img_list;
2613
2614 (void)ctxt;
2615
2616 if (argc != 1)
2617 {
2618 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2619 }
2620
2621 len = (int)grub_strlen(args[0]);
2622
2623 while (cur)
2624 {
2625 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2626 {
2627 break;
2628 }
2629 cur = cur->next;
2630 }
2631
2632 if (!cur)
2633 {
2634 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2635 }
2636
2637 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2638 grub_env_set("chosen", id);
2639 grub_env_export("chosen");
2640
2641 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2642 }
2643
2644 static char g_fake_vlnk_src[512];
2645 static char g_fake_vlnk_dst[512];
2646 static grub_uint64_t g_fake_vlnk_size;
2647 static grub_err_t ventoy_cmd_set_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2648 {
2649 (void)ctxt;
2650 (void)argc;
2651 (void)args;
2652
2653 g_fake_vlnk_size = (grub_uint64_t)grub_strtoull(args[2], NULL, 10);
2654
2655 grub_strncpy(g_fake_vlnk_dst, args[0], sizeof(g_fake_vlnk_dst));
2656 grub_snprintf(g_fake_vlnk_src, sizeof(g_fake_vlnk_src), "%s/________VENTOYVLNK.vlnk.%s", g_iso_path, args[1]);
2657
2658 grub_file_vtoy_vlnk(g_fake_vlnk_src, g_fake_vlnk_dst);
2659
2660 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2661 }
2662
2663 static grub_err_t ventoy_cmd_reset_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2664 {
2665 (void)ctxt;
2666 (void)argc;
2667 (void)args;
2668
2669 g_fake_vlnk_src[0] = 0;
2670 g_fake_vlnk_dst[0] = 0;
2671 g_fake_vlnk_size = 0;
2672 grub_file_vtoy_vlnk(NULL, NULL);
2673
2674 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2675 }
2676
2677
2678 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2679 {
2680 char value[32];
2681 char *pos = NULL;
2682 char *last = NULL;
2683 const char *id = NULL;
2684 img_info *cur = NULL;
2685
2686 (void)ctxt;
2687
2688 if (argc < 1 || argc > 3)
2689 {
2690 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2691 }
2692
2693 if (g_fake_vlnk_src[0] && g_fake_vlnk_dst[0])
2694 {
2695 pos = grub_strchr(g_fake_vlnk_src, '/');
2696 grub_env_set(args[0], pos);
2697 if (argc > 1)
2698 {
2699 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(g_fake_vlnk_size));
2700 grub_env_set(args[1], value);
2701 }
2702
2703 if (argc > 2)
2704 {
2705 for (last = pos; *pos; pos++)
2706 {
2707 if (*pos == '/')
2708 {
2709 last = pos;
2710 }
2711 }
2712 grub_env_set(args[2], last + 1);
2713 }
2714
2715 goto end;
2716 }
2717
2718 id = grub_env_get("chosen");
2719
2720 pos = grub_strstr(id, "VID_");
2721 if (pos)
2722 {
2723 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2724 }
2725 else
2726 {
2727 cur = g_ventoy_img_list;
2728 }
2729
2730 if (!cur)
2731 {
2732 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2733 }
2734
2735 grub_env_set(args[0], cur->path);
2736
2737 if (argc > 1)
2738 {
2739 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2740 grub_env_set(args[1], value);
2741 }
2742
2743 if (argc > 2)
2744 {
2745 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2746 grub_env_set(args[2], cur->name);
2747 }
2748
2749 end:
2750 g_svd_replace_offset = 0;
2751
2752 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2753 }
2754
2755
2756 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2757 {
2758 int len;
2759 grub_fs_t fs;
2760 grub_device_t dev = NULL;
2761 img_info *cur = NULL;
2762 img_info *tail = NULL;
2763 img_info *min = NULL;
2764 img_info *head = NULL;
2765 const char *strdata = NULL;
2766 char *device_name = NULL;
2767 char buf[32];
2768 img_iterator_node *node = NULL;
2769 img_iterator_node *tmp = NULL;
2770
2771 (void)ctxt;
2772
2773 if (argc != 2)
2774 {
2775 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2776 }
2777
2778 if (g_ventoy_img_list || g_ventoy_img_count)
2779 {
2780 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2781 }
2782
2783 VTOY_CMD_CHECK(1);
2784
2785 g_enumerate_time_checked = 0;
2786 g_enumerate_start_time_ms = grub_get_time_ms();
2787
2788 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2789 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2790 {
2791 g_filt_dot_underscore_file = 1;
2792 }
2793
2794 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2795 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2796 {
2797 g_sort_case_sensitive = 1;
2798 }
2799
2800 device_name = grub_file_get_device_name(args[0]);
2801 if (!device_name)
2802 {
2803 goto fail;
2804 }
2805
2806 g_enum_dev = dev = grub_device_open(device_name);
2807 if (!dev)
2808 {
2809 goto fail;
2810 }
2811
2812 g_enum_fs = fs = grub_fs_probe(dev);
2813 if (!fs)
2814 {
2815 goto fail;
2816 }
2817
2818 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2819 {
2820 debug("unsupported fs:<%s>\n", fs->name);
2821 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2822 goto fail;
2823 }
2824
2825 ventoy_set_env("vtoy_iso_fs", fs->name);
2826
2827 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2828 if (strdata && strdata[0] == '1')
2829 {
2830 g_default_menu_mode = 1;
2831 }
2832
2833 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2834
2835 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2836
2837 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2838 if (strdata && strdata[0] == '/')
2839 {
2840 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2841 if (g_img_iterator_head.dir[len - 1] != '/')
2842 {
2843 g_img_iterator_head.dir[len++] = '/';
2844 }
2845 g_img_iterator_head.dirlen = len;
2846 }
2847 else
2848 {
2849 g_img_iterator_head.dirlen = 1;
2850 grub_strcpy(g_img_iterator_head.dir, "/");
2851 }
2852
2853 g_img_iterator_head.tail = &tail;
2854
2855 if (g_img_max_search_level < 0)
2856 {
2857 g_img_max_search_level = GRUB_INT_MAX;
2858 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2859 if (strdata && ventoy_is_decimal(strdata))
2860 {
2861 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2862 }
2863 }
2864
2865 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2866 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2867 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2868 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2869 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2870 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2871
2872 for (node = &g_img_iterator_head; node; node = node->next)
2873 {
2874 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2875 }
2876
2877 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2878 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2879 {
2880 g_tree_view_menu_style = 1;
2881 }
2882
2883 ventoy_set_default_menu();
2884
2885 for (node = &g_img_iterator_head; node; node = node->next)
2886 {
2887 ventoy_dynamic_tree_menu(node);
2888 }
2889
2890 /* free node */
2891 node = g_img_iterator_head.next;
2892 while (node)
2893 {
2894 tmp = node->next;
2895 grub_free(node);
2896 node = tmp;
2897 }
2898
2899 /* sort image list by image name */
2900 while (g_ventoy_img_list)
2901 {
2902 min = g_ventoy_img_list;
2903 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2904 {
2905 if (ventoy_cmp_img(min, cur) > 0)
2906 {
2907 min = cur;
2908 }
2909 }
2910
2911 if (min->prev)
2912 {
2913 min->prev->next = min->next;
2914 }
2915
2916 if (min->next)
2917 {
2918 min->next->prev = min->prev;
2919 }
2920
2921 if (min == g_ventoy_img_list)
2922 {
2923 g_ventoy_img_list = min->next;
2924 }
2925
2926 if (head == NULL)
2927 {
2928 head = tail = min;
2929 min->prev = NULL;
2930 min->next = NULL;
2931 }
2932 else
2933 {
2934 tail->next = min;
2935 min->prev = tail;
2936 min->next = NULL;
2937 tail = min;
2938 }
2939 }
2940
2941 g_ventoy_img_list = head;
2942
2943 if (g_default_menu_mode == 1)
2944 {
2945 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2946 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2947 " echo 'return ...' \n"
2948 "}\n", "<--");
2949 }
2950
2951 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2952 {
2953 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2954 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2955 " %s_%s \n"
2956 "}\n",
2957 cur->unsupport ? "[***********] " : "",
2958 cur->alias ? cur->alias : cur->name, cur->class, cur,
2959 cur->menu_prefix,
2960 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2961 }
2962
2963 g_tree_script_buf[g_tree_script_pos] = 0;
2964 g_list_script_buf[g_list_script_pos] = 0;
2965
2966 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2967 grub_env_set(args[1], buf);
2968
2969 fail:
2970
2971 check_free(device_name, grub_free);
2972 check_free(dev, grub_device_close);
2973
2974 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2975 }
2976
2977 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2978 {
2979 grub_disk_t disk;
2980 char *device_name;
2981 char *pos;
2982 char *pos2;
2983
2984 device_name = grub_file_get_device_name(filename);
2985 if (!device_name)
2986 {
2987 return 1;
2988 }
2989
2990 pos = device_name;
2991 if (pos[0] == '(')
2992 {
2993 pos++;
2994 }
2995
2996 pos2 = grub_strstr(pos, ",");
2997 if (!pos2)
2998 {
2999 pos2 = grub_strstr(pos, ")");
3000 }
3001
3002 if (pos2)
3003 {
3004 *pos2 = 0;
3005 }
3006
3007 disk = grub_disk_open(pos);
3008 if (disk)
3009 {
3010 grub_disk_read(disk, 0, 0x180, 16, guid);
3011 grub_disk_read(disk, 0, 0x1b8, 4, signature);
3012 grub_disk_close(disk);
3013 }
3014 else
3015 {
3016 return 1;
3017 }
3018
3019 grub_free(device_name);
3020 return 0;
3021 }
3022
3023 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
3024 {
3025 eltorito_descriptor desc;
3026
3027 grub_memset(&desc, 0, sizeof(desc));
3028 grub_file_seek(file, 17 * 2048);
3029 grub_file_read(file, &desc, sizeof(desc));
3030
3031 if (desc.type != 0 || desc.version != 1)
3032 {
3033 return 0;
3034 }
3035
3036 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
3037 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
3038 {
3039 return 0;
3040 }
3041
3042 return desc.sector;
3043 }
3044
3045 static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector)
3046 {
3047 grub_uint8_t buf[512];
3048
3049 grub_file_seek(file, sector * 2048);
3050 grub_file_read(file, buf, sizeof(buf));
3051
3052 if (buf[0] == 0x01 && buf[1] == 0x00 &&
3053 buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88)
3054 {
3055 return *((grub_uint32_t *)(buf + 40));
3056 }
3057
3058 return 0;
3059 }
3060
3061 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
3062 {
3063 int i;
3064 int x86count = 0;
3065 grub_uint8_t buf[512];
3066 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
3067
3068 grub_file_seek(file, sector * 2048);
3069 grub_file_read(file, buf, sizeof(buf));
3070
3071 if (buf[0] == 0x01 && buf[1] == 0xEF)
3072 {
3073 debug("%s efi eltorito in Validation Entry\n", file->name);
3074 return 1;
3075 }
3076
3077 if (buf[0] == 0x01 && buf[1] == 0x00)
3078 {
3079 x86count++;
3080 }
3081
3082 for (i = 64; i < (int)sizeof(buf); i += 32)
3083 {
3084 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
3085 {
3086 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3087 return 1;
3088 }
3089
3090 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
3091 {
3092 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3093 return 1;
3094 }
3095 }
3096
3097 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
3098 {
3099 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
3100 {
3101 if (buf[36] == parttype[i])
3102 {
3103 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
3104 return 1;
3105 }
3106 }
3107 }
3108
3109 debug("%s does not contain efi eltorito\n", file->name);
3110 return 0;
3111 }
3112
3113 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
3114 {
3115 char *pos;
3116 const char *fs = NULL;
3117 const char *val = NULL;
3118 const char *cdprompt = NULL;
3119 grub_uint32_t i;
3120 grub_uint8_t chksum = 0;
3121 grub_disk_t disk;
3122
3123 disk = file->device->disk;
3124 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
3125
3126 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
3127 param->vtoy_disk_part_id = disk->partition->number + 1;
3128 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
3129
3130 pos = grub_strstr(file->name, "/");
3131 if (!pos)
3132 {
3133 pos = file->name;
3134 }
3135
3136 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
3137
3138 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
3139
3140 param->vtoy_img_size = file->size;
3141
3142 param->vtoy_reserved[0] = g_ventoy_break_level;
3143 param->vtoy_reserved[1] = g_ventoy_debug_level;
3144
3145 param->vtoy_reserved[2] = g_ventoy_chain_type;
3146
3147 /* Windows CD/DVD prompt 0:suppress 1:reserved */
3148 param->vtoy_reserved[4] = 0;
3149 if (g_ventoy_chain_type == 1) /* Windows */
3150 {
3151 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
3152 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
3153 {
3154 param->vtoy_reserved[4] = 1;
3155 }
3156 }
3157
3158 fs = ventoy_get_env("ventoy_fs_probe");
3159 if (fs && grub_strcmp(fs, "udf") == 0)
3160 {
3161 param->vtoy_reserved[3] = 1;
3162 }
3163
3164 param->vtoy_reserved[5] = 0;
3165 val = ventoy_get_env("VTOY_LINUX_REMOUNT");
3166 if (val && val[0] == '1' && val[1] == 0)
3167 {
3168 param->vtoy_reserved[5] = 1;
3169 }
3170
3171 /* ventoy_disk_signature used for vlnk */
3172 param->vtoy_reserved[6] = file->vlnk;
3173 grub_memcpy(param->vtoy_reserved + 7, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
3174
3175 /* calculate checksum */
3176 for (i = 0; i < sizeof(ventoy_os_param); i++)
3177 {
3178 chksum += *((grub_uint8_t *)param + i);
3179 }
3180 param->chksum = (grub_uint8_t)(0x100 - chksum);
3181
3182 return;
3183 }
3184
3185 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3186 {
3187 grub_uint32_t i = 0;
3188 grub_uint64_t total = 0;
3189 grub_uint64_t fileblk = 0;
3190 ventoy_img_chunk *chunk = NULL;
3191
3192 for (i = 0; i < chunklist->cur_chunk; i++)
3193 {
3194 chunk = chunklist->chunk + i;
3195
3196 if (chunk->disk_start_sector <= start)
3197 {
3198 debug("%u disk start invalid %lu\n", i, (ulong)start);
3199 return 1;
3200 }
3201
3202 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
3203 }
3204
3205 fileblk = (file->size + 511) / 512;
3206
3207 if (total != fileblk)
3208 {
3209 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
3210 if ((file->size % 512) && (total + 1 == fileblk))
3211 {
3212 debug("maybe img file to be processed.\n");
3213 return 0;
3214 }
3215
3216 return 1;
3217 }
3218
3219 return 0;
3220 }
3221
3222 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3223 {
3224 int fs_type;
3225 int len;
3226 grub_uint32_t i = 0;
3227 grub_uint32_t sector = 0;
3228 grub_uint32_t count = 0;
3229 grub_off_t size = 0;
3230 grub_off_t read = 0;
3231
3232 fs_type = ventoy_get_fs_type(file->fs->name);
3233 if (fs_type == ventoy_fs_exfat)
3234 {
3235 grub_fat_get_file_chunk(start, file, chunklist);
3236 }
3237 else if (fs_type == ventoy_fs_ext)
3238 {
3239 grub_ext_get_file_chunk(start, file, chunklist);
3240 }
3241 else
3242 {
3243 file->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read;
3244 file->read_hook_data = chunklist;
3245
3246 for (size = file->size; size > 0; size -= read)
3247 {
3248 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
3249 grub_file_read(file, NULL, read);
3250 }
3251
3252 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
3253 {
3254 chunklist->chunk[i].disk_start_sector += start;
3255 chunklist->chunk[i].disk_end_sector += start;
3256 }
3257
3258 if (ventoy_fs_udf == fs_type)
3259 {
3260 for (i = 0; i < chunklist->cur_chunk; i++)
3261 {
3262 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
3263 chunklist->chunk[i].img_start_sector = sector;
3264 chunklist->chunk[i].img_end_sector = sector + count - 1;
3265 sector += count;
3266 }
3267 }
3268 }
3269
3270 len = (int)grub_strlen(file->name);
3271 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
3272 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
3273 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
3274 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
3275 {
3276 for (i = 0; i < chunklist->cur_chunk; i++)
3277 {
3278 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
3279 if (count < 4)
3280 {
3281 count = 1;
3282 }
3283 else
3284 {
3285 count >>= 2;
3286 }
3287
3288 chunklist->chunk[i].img_start_sector = sector;
3289 chunklist->chunk[i].img_end_sector = sector + count - 1;
3290 sector += count;
3291 }
3292 }
3293
3294 return 0;
3295 }
3296
3297 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3298 {
3299 int rc;
3300 grub_file_t file;
3301 grub_disk_addr_t start;
3302
3303 (void)ctxt;
3304 (void)argc;
3305
3306 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3307 if (!file)
3308 {
3309 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3310 }
3311
3312 g_conf_replace_count = 0;
3313 grub_memset(g_conf_replace_node, 0, sizeof(g_conf_replace_node ));
3314 grub_memset(g_conf_replace_offset, 0, sizeof(g_conf_replace_offset ));
3315
3316 if (g_img_chunk_list.chunk)
3317 {
3318 grub_free(g_img_chunk_list.chunk);
3319 }
3320
3321 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
3322 {
3323 grub_file_close(file);
3324 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
3325 }
3326
3327 /* get image chunk data */
3328 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
3329 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3330 if (NULL == g_img_chunk_list.chunk)
3331 {
3332 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3333 }
3334
3335 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
3336 g_img_chunk_list.cur_chunk = 0;
3337
3338 start = file->device->disk->partition->start;
3339
3340 ventoy_get_block_list(file, &g_img_chunk_list, start);
3341
3342 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
3343 grub_file_close(file);
3344
3345 if (rc)
3346 {
3347 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
3348 }
3349
3350 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
3351 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
3352 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3353 }
3354
3355 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
3356 {
3357 int i;
3358 int n;
3359 grub_uint64_t offset = 0;
3360 grub_uint32_t align = 0;
3361 grub_file_t file = NULL;
3362 conf_replace *node = NULL;
3363 conf_replace *nodes[VTOY_MAX_CONF_REPLACE] = { NULL };
3364 ventoy_grub_param_file_replace *replace = NULL;
3365
3366 (void)ctxt;
3367 (void)argc;
3368 (void)args;
3369
3370 debug("select conf replace argc:%d\n", argc);
3371
3372 if (argc < 2)
3373 {
3374 return 0;
3375 }
3376
3377 n = ventoy_plugin_find_conf_replace(args[1], nodes);
3378 if (!n)
3379 {
3380 debug("Conf replace not found for %s\n", args[1]);
3381 goto end;
3382 }
3383
3384 debug("Find %d conf replace for %s\n", n, args[1]);
3385
3386 g_conf_replace_count = n;
3387 for (i = 0; i < n; i++)
3388 {
3389 node = nodes[i];
3390
3391 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3392 if (file)
3393 {
3394 offset = grub_iso9660_get_last_file_dirent_pos(file);
3395 grub_file_close(file);
3396 }
3397 else if (node->img > 0)
3398 {
3399 offset = 0;
3400 }
3401 else
3402 {
3403 debug("<(loop)%s> NOT exist\n", node->orgconf);
3404 continue;
3405 }
3406
3407 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3408 if (!file)
3409 {
3410 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3411 continue;
3412 }
3413
3414 align = ((int)file->size + 2047) / 2048 * 2048;
3415
3416 if (align > vtoy_max_replace_file_size)
3417 {
3418 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3419 grub_file_close(file);
3420 continue;
3421 }
3422
3423 grub_file_read(file, g_conf_replace_new_buf[i], file->size);
3424 grub_file_close(file);
3425 g_conf_replace_new_len[i] = (int)file->size;
3426 g_conf_replace_new_len_align[i] = align;
3427
3428 g_conf_replace_node[i] = node;
3429 g_conf_replace_offset[i] = offset + 2;
3430
3431 if (node->img > 0)
3432 {
3433 replace = &(g_grub_param->img_replace[i]);
3434 replace->magic = GRUB_IMG_REPLACE_MAGIC;
3435 grub_snprintf(replace->old_file_name[replace->old_name_cnt], 256, "%s", node->orgconf);
3436 replace->old_name_cnt++;
3437 }
3438
3439 debug("conf_replace OK: newlen[%d]: %d img:%d\n", i, g_conf_replace_new_len[i], node->img);
3440 }
3441
3442 end:
3443 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3444 }
3445
3446 static int ventoy_var_expand(int *record, int *flag, const char *var, char *expand, int len)
3447 {
3448 int i = 0;
3449 int n = 0;
3450 char c;
3451 const char *ch = var;
3452
3453 *record = 0;
3454 expand[0] = 0;
3455
3456 while (*ch)
3457 {
3458 if (*ch == '_' || (*ch >= '0' && *ch <= '9') || (*ch >= 'A' && *ch <= 'Z') || (*ch >= 'a' && *ch <= 'z'))
3459 {
3460 ch++;
3461 n++;
3462 }
3463 else
3464 {
3465 debug("Invalid variable letter <%c>\n", *ch);
3466 goto end;
3467 }
3468 }
3469
3470 if (n > 32)
3471 {
3472 debug("Invalid variable length:%d <%s>\n", n, var);
3473 goto end;
3474 }
3475
3476 if (grub_strncmp(var, "VT_", 3) == 0) /* built-in variables */
3477 {
3478
3479 }
3480 else
3481 {
3482 if (*flag == 0)
3483 {
3484 *flag = 1;
3485 grub_printf("\n=================== Variables Expansion ===================\n\n");
3486 }
3487
3488 grub_printf("<%s>: ", var);
3489 grub_refresh();
3490
3491 while (i < (len - 1))
3492 {
3493 c = grub_getkey();
3494 if ((c == '\n') || (c == '\r'))
3495 {
3496 if (i > 0)
3497 {
3498 grub_printf("\n");
3499 grub_refresh();
3500 *record = 1;
3501 break;
3502 }
3503 }
3504 else if (grub_isprint(c))
3505 {
3506 if (i + 1 < (len - 1))
3507 {
3508 grub_printf("%c", c);
3509 grub_refresh();
3510 expand[i++] = c;
3511 expand[i] = 0;
3512 }
3513 }
3514 else if (c == '\b')
3515 {
3516 if (i > 0)
3517 {
3518 expand[i - 1] = ' ';
3519 grub_printf("\r<%s>: %s", var, expand);
3520
3521 expand[i - 1] = 0;
3522 grub_printf("\r<%s>: %s", var, expand);
3523
3524 grub_refresh();
3525 i--;
3526 }
3527 }
3528 }
3529 }
3530
3531 end:
3532 if (expand[0] == 0)
3533 {
3534 grub_snprintf(expand, len, "$$%s$$", var);
3535 }
3536
3537 return 0;
3538 }
3539
3540 static int ventoy_auto_install_var_expand(install_template *node)
3541 {
3542 int pos = 0;
3543 int flag = 0;
3544 int record = 0;
3545 int newlen = 0;
3546 char *start = NULL;
3547 char *end = NULL;
3548 char *newbuf = NULL;
3549 char *curline = NULL;
3550 char *nextline = NULL;
3551 grub_uint8_t *code = NULL;
3552 char value[512];
3553 var_node *CurNode = NULL;
3554 var_node *pVarList = NULL;
3555
3556 code = (grub_uint8_t *)node->filebuf;
3557
3558 if (node->filelen >= VTOY_SIZE_1MB)
3559 {
3560 debug("auto install script too long %d\n", node->filelen);
3561 return 0;
3562 }
3563
3564 if ((code[0] == 0xff && code[1] == 0xfe) || (code[0] == 0xfe && code[1] == 0xff))
3565 {
3566 debug("UCS-2 encoding NOT supported\n");
3567 return 0;
3568 }
3569
3570 start = grub_strstr(node->filebuf, "$$");
3571 if (!start)
3572 {
3573 debug("no need to expand variable, no start.\n");
3574 return 0;
3575 }
3576
3577 end = grub_strstr(start + 2, "$$");
3578 if (!end)
3579 {
3580 debug("no need to expand variable, no end.\n");
3581 return 0;
3582 }
3583
3584 newlen = grub_max(node->filelen * 10, VTOY_SIZE_128KB);
3585 newbuf = grub_malloc(newlen);
3586 if (!newbuf)
3587 {
3588 debug("Failed to alloc newbuf %d\n", newlen);
3589 return 0;
3590 }
3591
3592 for (curline = node->filebuf; curline; curline = nextline)
3593 {
3594 nextline = ventoy_get_line(curline);
3595
3596 start = grub_strstr(curline, "$$");
3597 if (start)
3598 {
3599 end = grub_strstr(start + 2, "$$");
3600 }
3601
3602 if (start && end)
3603 {
3604 *start = *end = 0;
3605 VTOY_APPEND_NEWBUF(curline);
3606
3607 for (CurNode = pVarList; CurNode; CurNode = CurNode->next)
3608 {
3609 if (grub_strcmp(start + 2, CurNode->var) == 0)
3610 {
3611 grub_snprintf(value, sizeof(value) - 1, "%s", CurNode->val);
3612 break;
3613 }
3614 }
3615
3616 if (!CurNode)
3617 {
3618 value[sizeof(value) - 1] = 0;
3619 ventoy_var_expand(&record, &flag, start + 2, value, sizeof(value) - 1);
3620
3621 if (record)
3622 {
3623 CurNode = grub_zalloc(sizeof(var_node));
3624 if (CurNode)
3625 {
3626 grub_snprintf(CurNode->var, sizeof(CurNode->var), "%s", start + 2);
3627 grub_snprintf(CurNode->val, sizeof(CurNode->val), "%s", value);
3628 CurNode->next = pVarList;
3629 pVarList = CurNode;
3630 }
3631 }
3632 }
3633
3634 VTOY_APPEND_NEWBUF(value);
3635
3636 VTOY_APPEND_NEWBUF(end + 2);
3637 }
3638 else
3639 {
3640 VTOY_APPEND_NEWBUF(curline);
3641 }
3642
3643 if (pos > 0 && newbuf[pos - 1] == '\r')
3644 {
3645 newbuf[pos - 1] = '\n';
3646 }
3647 else
3648 {
3649 newbuf[pos++] = '\n';
3650 }
3651 }
3652
3653 grub_free(node->filebuf);
3654 node->filebuf = newbuf;
3655 node->filelen = pos;
3656
3657 while (pVarList)
3658 {
3659 CurNode = pVarList->next;
3660 grub_free(pVarList);
3661 pVarList = CurNode;
3662 }
3663
3664 return 0;
3665 }
3666
3667 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3668 {
3669 int i = 0;
3670 int pos = 0;
3671 int defidx = 1;
3672 char *buf = NULL;
3673 grub_file_t file = NULL;
3674 char configfile[128];
3675 install_template *node = NULL;
3676
3677 (void)ctxt;
3678 (void)argc;
3679 (void)args;
3680
3681 debug("select auto installation argc:%d\n", argc);
3682
3683 if (argc < 1)
3684 {
3685 return 0;
3686 }
3687
3688 node = ventoy_plugin_find_install_template(args[0]);
3689 if (!node)
3690 {
3691 debug("Auto install template not found for %s\n", args[0]);
3692 return 0;
3693 }
3694
3695 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3696 {
3697 defidx = node->autosel;
3698 if (node->timeout < 0)
3699 {
3700 node->cursel = node->autosel - 1;
3701 debug("Auto install template auto select %d\n", node->autosel);
3702 goto load;
3703 }
3704 }
3705
3706 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3707 if (!buf)
3708 {
3709 return 0;
3710 }
3711
3712 if (node->timeout > 0)
3713 {
3714 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3715 }
3716
3717 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" --class=\"sel_auto_install\" {\n"
3718 " echo %s\n}\n", "");
3719
3720 for (i = 0; i < node->templatenum; i++)
3721 {
3722 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" --class=\"sel_auto_install\" {\n"
3723 " echo \"\"\n}\n",
3724 node->templatepath[i].path);
3725 }
3726
3727 g_ventoy_menu_esc = 1;
3728 g_ventoy_suppress_esc = 1;
3729 g_ventoy_suppress_esc_default = defidx;
3730
3731 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3732 grub_script_execute_sourcecode(configfile);
3733
3734 g_ventoy_menu_esc = 0;
3735 g_ventoy_suppress_esc = 0;
3736 g_ventoy_suppress_esc_default = 1;
3737
3738 grub_free(buf);
3739
3740 node->cursel = g_ventoy_last_entry - 1;
3741
3742 load:
3743 grub_check_free(node->filebuf);
3744 node->filelen = 0;
3745
3746 if (node->cursel >= 0 && node->cursel < node->templatenum)
3747 {
3748 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"),
3749 node->templatepath[node->cursel].path);
3750 if (file)
3751 {
3752 node->filebuf = grub_malloc(file->size + 8);
3753 if (node->filebuf)
3754 {
3755 grub_file_read(file, node->filebuf, file->size);
3756 grub_file_close(file);
3757
3758 grub_memset(node->filebuf + file->size, 0, 8);
3759 node->filelen = (int)file->size;
3760
3761 ventoy_auto_install_var_expand(node);
3762 }
3763 }
3764 else
3765 {
3766 debug("Failed to open auto install script <%s%s>\n",
3767 ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path);
3768 }
3769 }
3770
3771 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3772 }
3773
3774 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3775 {
3776 int i = 0;
3777 int pos = 0;
3778 int defidx = 1;
3779 char *buf = NULL;
3780 char configfile[128];
3781 persistence_config *node;
3782
3783 (void)ctxt;
3784 (void)argc;
3785 (void)args;
3786
3787 debug("select persistence argc:%d\n", argc);
3788
3789 if (argc < 1)
3790 {
3791 return 0;
3792 }
3793
3794 node = ventoy_plugin_find_persistent(args[0]);
3795 if (!node)
3796 {
3797 debug("Persistence image not found for %s\n", args[0]);
3798 return 0;
3799 }
3800
3801 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3802 {
3803 defidx = node->autosel;
3804 if (node->timeout < 0)
3805 {
3806 node->cursel = node->autosel - 1;
3807 debug("Persistence image auto select %d\n", node->autosel);
3808 return 0;
3809 }
3810 }
3811
3812 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3813 if (!buf)
3814 {
3815 return 0;
3816 }
3817
3818 if (node->timeout > 0)
3819 {
3820 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3821 }
3822
3823 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" --class=\"sel_persistence\" {\n"
3824 " echo %s\n}\n", "");
3825
3826 for (i = 0; i < node->backendnum; i++)
3827 {
3828 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" --class=\"sel_persistence\" {\n"
3829 " echo \"\"\n}\n",
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
4977 (void)argc;
4978 (void)ctxt;
4979
4980 ret = ventoy_load_part_table(args[0]);
4981 if (ret)
4982 {
4983 grub_exit();
4984 }
4985
4986 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4987 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4988
4989 return 0;
4990 }
4991
4992 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4993 {
4994 int ret = 1;
4995 const char *vcfg = NULL;
4996
4997 (void)argc;
4998 (void)ctxt;
4999
5000 vcfg = ventoy_plugin_get_custom_boot(args[0]);
5001 if (vcfg)
5002 {
5003 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
5004 grub_env_set(args[1], vcfg);
5005 ret = 0;
5006 }
5007 else
5008 {
5009 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
5010 }
5011
5012 grub_errno = 0;
5013 return ret;
5014 }
5015
5016
5017 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
5018 {
5019 int id;
5020 grub_uint8_t zeroguid[16] = {0};
5021
5022 (void)argc;
5023 (void)ctxt;
5024
5025 id = (int)grub_strtoul(args[0], NULL, 10);
5026 grub_errno = 0;
5027
5028 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
5029 {
5030 if (id >= 1 && id <= 128)
5031 {
5032 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
5033 {
5034 return 0;
5035 }
5036 }
5037 }
5038 else
5039 {
5040 if (id >= 1 && id <= 4)
5041 {
5042 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
5043 {
5044 return 0;
5045 }
5046 }
5047 }
5048
5049 return 1;
5050 }
5051
5052 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
5053 {
5054 int rc = 1;
5055 char *device_name = NULL;
5056 grub_device_t dev = NULL;
5057 grub_fs_t fs = NULL;
5058 char *label = NULL;
5059
5060 (void)ctxt;
5061
5062 debug("get fs label for %s\n", args[0]);
5063
5064 if (argc != 2)
5065 {
5066 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
5067 return 1;
5068 }
5069
5070 device_name = grub_file_get_device_name(args[0]);
5071 if (!device_name)
5072 {
5073 debug("grub_file_get_device_name failed, %s\n", args[0]);
5074 goto end;
5075 }
5076
5077 dev = grub_device_open(device_name);
5078 if (!dev)
5079 {
5080 debug("grub_device_open failed, %s\n", device_name);
5081 goto end;
5082 }
5083
5084 fs = grub_fs_probe(dev);
5085 if (NULL == fs || NULL == fs->fs_label)
5086 {
5087 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
5088 goto end;
5089 }
5090
5091 fs->fs_label(dev, &label);
5092 if (label)
5093 {
5094 debug("label=<%s>\n", label);
5095 ventoy_set_env(args[1], label);
5096 grub_free(label);
5097 }
5098
5099 rc = 0;
5100
5101 end:
5102
5103 check_free(device_name, grub_free);
5104 check_free(dev, grub_device_close);
5105
5106 return rc;
5107 }
5108
5109 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5110 {
5111 if (!info->dir)
5112 {
5113 grub_snprintf((char *)data, 256, "%s", filename);
5114 return 1;
5115 }
5116
5117 return 0;
5118 }
5119
5120 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5121 {
5122 if (info->dir && filename && filename[0] != '.')
5123 {
5124 grub_snprintf((char *)data, 256, "%s", filename);
5125 return 1;
5126 }
5127
5128 return 0;
5129 }
5130
5131 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
5132 {
5133 int rc = 1;
5134 char *device_name = NULL;
5135 grub_device_t dev = NULL;
5136 grub_fs_t fs = NULL;
5137 char name[256] ={0};
5138
5139 if (argc != 3)
5140 {
5141 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
5142 return 1;
5143 }
5144
5145 device_name = grub_file_get_device_name(args[0]);
5146 if (!device_name)
5147 {
5148 debug("grub_file_get_device_name failed, %s\n", args[0]);
5149 goto end;
5150 }
5151
5152 dev = grub_device_open(device_name);
5153 if (!dev)
5154 {
5155 debug("grub_device_open failed, %s\n", device_name);
5156 goto end;
5157 }
5158
5159 fs = grub_fs_probe(dev);
5160 if (!fs)
5161 {
5162 debug("grub_fs_probe failed, %s\n", device_name);
5163 goto end;
5164 }
5165
5166 fs->fs_dir(dev, args[1], hook, name);
5167 if (name[0])
5168 {
5169 ventoy_set_env(args[2], name);
5170 }
5171
5172 rc = 0;
5173
5174 end:
5175
5176 check_free(device_name, grub_free);
5177 check_free(dev, grub_device_close);
5178
5179 return rc;
5180 }
5181
5182 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
5183 {
5184 (void)ctxt;
5185 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
5186 }
5187
5188 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
5189 {
5190 (void)ctxt;
5191 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
5192 }
5193
5194 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
5195 {
5196 char c;
5197 char *pos = NULL;
5198 char *end = NULL;
5199
5200 (void)ctxt;
5201
5202 if (argc != 2)
5203 {
5204 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
5205 return 1;
5206 }
5207
5208 for (pos = args[0]; *pos; pos++)
5209 {
5210 if (*pos == '.')
5211 {
5212 end = pos;
5213 }
5214 }
5215
5216 if (end)
5217 {
5218 c = *end;
5219 *end = 0;
5220 }
5221
5222 grub_env_set(args[1], args[0]);
5223
5224 if (end)
5225 {
5226 *end = c;
5227 }
5228
5229 return 0;
5230 }
5231
5232 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
5233 {
5234 int i;
5235 int len;
5236 const char *buf;
5237
5238 (void)ctxt;
5239
5240 if (argc != 2)
5241 {
5242 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
5243 return 1;
5244 }
5245
5246 buf = args[0];
5247 len = (int)grub_strlen(buf);
5248 for (i = len; i > 0; i--)
5249 {
5250 if (buf[i - 1] == '/')
5251 {
5252 grub_env_set(args[1], buf + i);
5253 return 0;
5254 }
5255 }
5256
5257 grub_env_set(args[1], buf);
5258
5259 return 0;
5260 }
5261
5262 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5263 {
5264 struct grub_video_mode_info info;
5265 char buf[32];
5266
5267 (void)ctxt;
5268 (void)argc;
5269 (void)args;
5270
5271 if (!g_video_mode_list)
5272 {
5273 ventoy_enum_video_mode();
5274 }
5275
5276 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5277 {
5278 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
5279 }
5280 else
5281 {
5282 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
5283 }
5284
5285 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
5286
5287 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
5288 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
5289
5290 VENTOY_CMD_RETURN(0);
5291 }
5292
5293 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5294 {
5295 struct grub_video_mode_info info;
5296 char buf[32];
5297
5298 (void)ctxt;
5299 (void)argc;
5300 (void)args;
5301
5302 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5303 {
5304 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
5305 }
5306 else
5307 {
5308 grub_snprintf(buf, sizeof(buf), "0x0x0");
5309 }
5310
5311 grub_env_set(args[0], buf);
5312
5313 VENTOY_CMD_RETURN(0);
5314 }
5315
5316 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5317 {
5318 int id;
5319 char buf[32];
5320
5321 (void)ctxt;
5322 (void)argc;
5323
5324 if (!g_video_mode_list)
5325 {
5326 return 0;
5327 }
5328
5329 id = (int)grub_strtoul(args[0], NULL, 10);
5330 if (id < g_video_mode_num)
5331 {
5332 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5333 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5334 }
5335
5336 grub_env_set(args[1], buf);
5337
5338 VENTOY_CMD_RETURN(0);
5339 }
5340
5341 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5342 {
5343 grub_uint32_t i;
5344 grub_uint32_t loadsector = 0;
5345 grub_file_t file;
5346 char value[32];
5347 grub_uint32_t boot_catlog = 0;
5348 grub_uint8_t buf[512];
5349
5350 (void)ctxt;
5351
5352 if (argc != 2)
5353 {
5354 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5355 return 1;
5356 }
5357
5358 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5359 if (!file)
5360 {
5361 debug("failed to open %s\n", args[0]);
5362 return 1;
5363 }
5364
5365 boot_catlog = ventoy_get_iso_boot_catlog(file);
5366 if (boot_catlog == 0)
5367 {
5368 debug("No bootcatlog found\n");
5369 grub_file_close(file);
5370 return 1;
5371 }
5372
5373 grub_memset(buf, 0, sizeof(buf));
5374 grub_file_seek(file, boot_catlog * 2048);
5375 grub_file_read(file, buf, sizeof(buf));
5376 grub_file_close(file);
5377
5378 for (i = 0; i < sizeof(buf); i += 32)
5379 {
5380 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5381 {
5382 if (buf[i + 32] == 0x88)
5383 {
5384 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5385 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5386 break;
5387 }
5388 }
5389 }
5390
5391 if (loadsector == 0)
5392 {
5393 debug("No EFI eltorito info found\n");
5394 return 1;
5395 }
5396
5397 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5398 grub_env_set(args[1], value);
5399 VENTOY_CMD_RETURN(0);
5400 }
5401
5402 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5403 {
5404 int curpos;
5405 int printlen;
5406 grub_size_t len;
5407 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5408
5409 if (pfsdir->initrd[0])
5410 {
5411 return 1;
5412 }
5413
5414 curpos = pfsdir->curpos;
5415 len = grub_strlen(filename);
5416
5417 if (info->dir)
5418 {
5419 if ((len == 1 && filename[0] == '.') ||
5420 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5421 {
5422 return 0;
5423 }
5424
5425 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5426 pfsdir->dircnt++;
5427
5428 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5429 pfsdir->curpos = curpos + printlen;
5430 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5431 pfsdir->curpos = curpos;
5432 pfsdir->fullpath[curpos] = 0;
5433 }
5434 else
5435 {
5436 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5437 pfsdir->filecnt++;
5438
5439 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5440 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5441 {
5442 if (info->size > 32 * VTOY_SIZE_1MB)
5443 {
5444 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5445 return 1;
5446 }
5447 }
5448 }
5449
5450 return 0;
5451 }
5452
5453 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5454 {
5455 int i;
5456 char *pos = NULL;
5457 char *device_name = NULL;
5458 grub_device_t dev = NULL;
5459 grub_fs_t fs = NULL;
5460 replace_fs_dir *pfsdir = NULL;
5461
5462 (void)ctxt;
5463
5464 if (argc != 2)
5465 {
5466 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5467 return 1;
5468 }
5469
5470 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5471 if (!pfsdir)
5472 {
5473 return 1;
5474 }
5475
5476 device_name = grub_file_get_device_name(args[0]);
5477 if (!device_name)
5478 {
5479 goto fail;
5480 }
5481
5482 dev = grub_device_open(device_name);
5483 if (!dev)
5484 {
5485 goto fail;
5486 }
5487
5488 fs = grub_fs_probe(dev);
5489 if (!fs)
5490 {
5491 goto fail;
5492 }
5493
5494 pfsdir->dev = dev;
5495 pfsdir->fs = fs;
5496 pfsdir->curpos = 1;
5497 pfsdir->fullpath[0] = '/';
5498 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5499
5500 if (pfsdir->initrd[0])
5501 {
5502 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5503
5504 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5505 {
5506 if (pfsdir->initrd[i] == '/')
5507 {
5508 pfsdir->initrd[i] = '\\';
5509 }
5510 }
5511
5512 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5513 grub_env_set(args[1], pos);
5514 }
5515 else
5516 {
5517 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5518 }
5519
5520 fail:
5521
5522 grub_check_free(pfsdir);
5523 grub_check_free(device_name);
5524 check_free(dev, grub_device_close);
5525
5526 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5527 }
5528
5529 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5530 {
5531 const char *pager = NULL;
5532
5533 (void)ctxt;
5534 (void)argc;
5535 (void)args;
5536
5537 pager = grub_env_get("pager");
5538 if (NULL == pager)
5539 {
5540 g_pager_flag = 1;
5541 grub_env_set("pager", "1");
5542 }
5543 else if (pager[0] == '1')
5544 {
5545 g_pager_flag = 0;
5546 }
5547 else
5548 {
5549 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5550 g_pager_flag = 2;
5551 grub_env_set("pager", "1");
5552 }
5553
5554 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5555 }
5556
5557 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5558 {
5559 (void)ctxt;
5560 (void)argc;
5561 (void)args;
5562
5563 if (g_pager_flag == 1)
5564 {
5565 grub_env_unset("pager");
5566 }
5567 else if (g_pager_flag == 2)
5568 {
5569 grub_env_set("pager", g_old_pager);
5570 }
5571
5572 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5573 }
5574
5575 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5576 {
5577 if (g_json_case_mis_path[0])
5578 {
5579 return 1;
5580 }
5581
5582 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5583 {
5584 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5585 return 1;
5586 }
5587 return 0;
5588 }
5589
5590 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5591 {
5592 char path[16];
5593 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5594
5595 if (g_json_case_mis_path[0])
5596 {
5597 return 1;
5598 }
5599
5600 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5601 {
5602 if (grub_strcasecmp(filename, "ventoy") == 0)
5603 {
5604 grub_snprintf(path, sizeof(path), "/%s", filename);
5605 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5606 if (g_json_case_mis_path[0])
5607 {
5608 return 1;
5609 }
5610 }
5611 }
5612
5613 return 0;
5614 }
5615
5616 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5617 {
5618 int fstype = 0;
5619 char *device_name = NULL;
5620 grub_device_t dev = NULL;
5621 grub_fs_t fs = NULL;
5622 chk_case_fs_dir fs_dir;
5623
5624 (void)ctxt;
5625 (void)argc;
5626 (void)args;
5627
5628 device_name = grub_file_get_device_name(args[0]);
5629 if (!device_name)
5630 {
5631 goto out;
5632 }
5633
5634 dev = grub_device_open(device_name);
5635 if (!dev)
5636 {
5637 goto out;
5638 }
5639
5640 fs = grub_fs_probe(dev);
5641 if (!fs)
5642 {
5643 goto out;
5644 }
5645
5646 fstype = ventoy_get_fs_type(fs->name);
5647 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5648 {
5649 goto out;
5650 }
5651
5652 g_json_case_mis_path[0] = 0;
5653 fs_dir.dev = dev;
5654 fs_dir.fs = fs;
5655 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5656
5657 if (g_json_case_mis_path[0])
5658 {
5659 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5660 }
5661
5662 out:
5663
5664 grub_check_free(device_name);
5665 check_free(dev, grub_device_close);
5666
5667 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5668 }
5669
5670 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5671 {
5672 grub_disk_t disk;
5673 grub_partition_t part;
5674 char priority_str[3]; /* Maximum value 15 */
5675
5676 (void)ctxt;
5677
5678 if (argc < 2 || argc > 3)
5679 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5680 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5681
5682 /* Open the disk if it exists */
5683 disk = grub_disk_open (args[0]);
5684 if (!disk)
5685 {
5686 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5687 "Not a disk");
5688 }
5689
5690 part = grub_partition_probe (disk, args[1]);
5691 if (!part)
5692 {
5693 grub_disk_close (disk);
5694 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5695 "No such partition");
5696 }
5697
5698 if (grub_strcmp (part->partmap->name, "gpt"))
5699 {
5700 grub_disk_close (disk);
5701 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5702 "Not a GPT partition");
5703 }
5704
5705 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5706 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5707
5708 if (argc == 3)
5709 {
5710 grub_env_set (args[2], priority_str);
5711 grub_env_export (args[2]);
5712 }
5713 else
5714 {
5715 grub_printf ("Priority is %s\n", priority_str);
5716 }
5717
5718 grub_disk_close (disk);
5719 return GRUB_ERR_NONE;
5720 }
5721
5722
5723 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5724 {
5725 int ret = 1;
5726 int joliet = 0;
5727 grub_file_t file = NULL;
5728 grub_uint32_t loadrba = 0;
5729 grub_uint32_t boot_catlog = 0;
5730 grub_uint8_t sector[512];
5731 boot_info_table *info = NULL;
5732
5733 (void)ctxt;
5734 (void)argc;
5735
5736 /* This also trigger a iso9660 fs parse */
5737 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5738 {
5739 return 0;
5740 }
5741
5742 joliet = grub_iso9660_is_joliet();
5743 if (joliet == 0)
5744 {
5745 return 1;
5746 }
5747
5748 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5749 if (!file)
5750 {
5751 debug("failed to open %s\n", args[0]);
5752 return 1;
5753 }
5754
5755 boot_catlog = ventoy_get_iso_boot_catlog(file);
5756 if (boot_catlog == 0)
5757 {
5758 debug("no bootcatlog found %u\n", boot_catlog);
5759 goto out;
5760 }
5761
5762 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5763 if (loadrba == 0)
5764 {
5765 debug("no bios eltorito rba found %u\n", loadrba);
5766 goto out;
5767 }
5768
5769 grub_file_seek(file, loadrba * 2048);
5770 grub_file_read(file, sector, 512);
5771
5772 info = (boot_info_table *)sector;
5773 if (info->bi_data0 == 0x7c6ceafa &&
5774 info->bi_data1 == 0x90900000 &&
5775 info->bi_PrimaryVolumeDescriptor == 16 &&
5776 info->bi_BootFileLocation == loadrba)
5777 {
5778 debug("bootloader is syslinux, %u.\n", loadrba);
5779 ret = 0;
5780 }
5781
5782 out:
5783
5784 grub_file_close(file);
5785 grub_errno = GRUB_ERR_NONE;
5786 return ret;
5787 }
5788
5789 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5790 {
5791 int n = 0;
5792 ventoy_vlnk_part *node;
5793
5794 (void)ctxt;
5795 (void)argc;
5796 (void)args;
5797
5798 for (node = g_vlnk_part_list; node; node = node->next)
5799 {
5800 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5801 ++n, node->device, node->disksig,
5802 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5803 }
5804
5805 return 0;
5806 }
5807
5808 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5809 {
5810 int len = 0;
5811
5812 (void)ctxt;
5813
5814 if (argc == 1)
5815 {
5816 len = (int)grub_strlen(args[0]);
5817 if (grub_file_is_vlnk_suffix(args[0], len))
5818 {
5819 return 0;
5820 }
5821 }
5822
5823 return 1;
5824 }
5825
5826 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5827 {
5828 int vlnk = 0;
5829 const char *name = NULL;
5830
5831 (void)ctxt;
5832
5833 if (argc == 2)
5834 {
5835 grub_env_unset(args[1]);
5836 name = grub_file_get_vlnk(args[0], &vlnk);
5837 if (vlnk)
5838 {
5839 debug("VLNK SRC: <%s>\n", args[0]);
5840 debug("VLNK DST: <%s>\n", name);
5841 grub_env_set(args[1], name);
5842 return 0;
5843 }
5844 }
5845
5846 return 1;
5847 }
5848
5849 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5850 {
5851 int ret = 1;
5852 int len = 0;
5853 grub_file_t file = NULL;
5854 ventoy_vlnk vlnk;
5855 char dst[512];
5856
5857 (void)ctxt;
5858
5859 if (argc != 1)
5860 {
5861 goto out;
5862 }
5863
5864 len = (int)grub_strlen(args[0]);
5865 if (!grub_file_is_vlnk_suffix(args[0], len))
5866 {
5867 grub_printf("Invalid vlnk suffix\n");
5868 goto out;
5869 }
5870
5871 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5872 if (!file)
5873 {
5874 grub_printf("Failed to open %s\n", args[0]);
5875 goto out;
5876 }
5877
5878 if (file->size != 32768)
5879 {
5880 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5881 goto out;
5882 }
5883
5884 grub_memset(&vlnk, 0, sizeof(vlnk));
5885 grub_file_read(file, &vlnk, sizeof(vlnk));
5886
5887 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5888
5889 out:
5890
5891 grub_refresh();
5892 check_free(file, grub_file_close);
5893 grub_errno = GRUB_ERR_NONE;
5894 return ret;
5895 }
5896
5897 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5898 {
5899 (void)ctxt;
5900 (void)argc;
5901 (void)args;
5902
5903 g_iso_vd_id_publisher[0] = 0;
5904 g_iso_vd_id_prepare[0] = 0;
5905 g_iso_vd_id_application[0] = 0;
5906
5907 return 0;
5908 }
5909
5910 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
5911 {
5912 int ret = 1;
5913 int offset = 318;
5914 grub_file_t file = NULL;
5915
5916 (void)ctxt;
5917 (void)argc;
5918
5919 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5920 if (!file)
5921 {
5922 grub_printf("Failed to open %s\n", args[0]);
5923 goto out;
5924 }
5925
5926 grub_file_seek(file, 16 * 2048 + offset);
5927 grub_file_read(file, g_iso_vd_id_publisher, 128);
5928
5929 offset += 128;
5930 grub_file_seek(file, 16 * 2048 + offset);
5931 grub_file_read(file, g_iso_vd_id_prepare, 128);
5932
5933 offset += 128;
5934 grub_file_seek(file, 16 * 2048 + offset);
5935 grub_file_read(file, g_iso_vd_id_application, 128);
5936
5937 out:
5938
5939 check_free(file, grub_file_close);
5940 grub_errno = GRUB_ERR_NONE;
5941 return ret;
5942 }
5943
5944 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
5945 {
5946 int ret = 1;
5947 char *id = g_iso_vd_id_publisher;
5948
5949 (void)ctxt;
5950 (void)argc;
5951
5952 if (args[0][0] == '1')
5953 {
5954 id = g_iso_vd_id_prepare;
5955 }
5956 else if (args[0][0] == '2')
5957 {
5958 id = g_iso_vd_id_application;
5959 }
5960
5961 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
5962 {
5963 ret = 0;
5964 }
5965
5966 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
5967 {
5968 ret = 0;
5969 }
5970
5971 grub_errno = GRUB_ERR_NONE;
5972 return ret;
5973 }
5974
5975 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
5976 {
5977 (void)ctxt;
5978 (void)argc;
5979
5980 g_ventoy_fn_mutex = 0;
5981 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
5982 {
5983 g_ventoy_fn_mutex = 1;
5984 }
5985
5986 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5987 }
5988
5989 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
5990 {
5991 grub_uint64_t total;
5992 grub_uint64_t org_required;
5993 grub_uint64_t new_required;
5994
5995 (void)ctxt;
5996 (void)argc;
5997 (void)args;
5998
5999 #ifdef GRUB_MACHINE_EFI
6000 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
6001 grub_printf("Total pages: %llu\n", (unsigned long long)total);
6002 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
6003 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
6004 #else
6005 (void)total;
6006 (void)org_required;
6007 (void)new_required;
6008 grub_printf("Non EFI mode!\n");
6009 #endif
6010
6011 grub_refresh();
6012
6013 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6014 }
6015
6016 static grub_err_t ventoy_cmd_need_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
6017 {
6018 const char *env = NULL;
6019
6020 (void)ctxt;
6021 (void)argc;
6022
6023 if (g_ventoy_memdisk_mode || g_ventoy_grub2_mode || g_ventoy_wimboot_mode || g_ventoy_iso_raw)
6024 {
6025 return 1;
6026 }
6027
6028 if (ventoy_check_mode_by_name(args[0], "vtmemdisk") ||
6029 ventoy_check_mode_by_name(args[0], "vtgrub2") ||
6030 ventoy_check_mode_by_name(args[0], "vtwimboot"))
6031 {
6032 return 1;
6033 }
6034
6035 env = grub_env_get("VTOY_SECONDARY_BOOT_MENU");
6036 if (env && env[0] == '0' && env[1] == 0)
6037 {
6038 return 1;
6039 }
6040
6041 return 0;
6042 }
6043
6044 static grub_err_t ventoy_cmd_show_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
6045 {
6046 int n = 0;
6047 int pos = 0;
6048 int len = 0;
6049 int select = 0;
6050 int timeout = 0;
6051 char *cmd = NULL;
6052 const char *env = NULL;
6053 ulonglong fsize = 0;
6054 char cfgfile[128];
6055 int seldata[16] = {0};
6056
6057 (void)ctxt;
6058 (void)argc;
6059
6060 len = 8 * VTOY_SIZE_1KB;
6061 cmd = (char *)grub_malloc(len);
6062 if (!cmd)
6063 {
6064 return 1;
6065 }
6066
6067 g_vtoy_secondary_need_recover = 0;
6068 grub_env_unset("VTOY_CHKSUM_FILE_PATH");
6069
6070 env = grub_env_get("VTOY_SECONDARY_TIMEOUT");
6071 if (env)
6072 {
6073 timeout = (int)grub_strtol(env, NULL, 10);
6074 }
6075
6076 if (timeout > 0)
6077 {
6078 vtoy_len_ssprintf(cmd, pos, len, "set timeout=%d\n", timeout);
6079 }
6080
6081 fsize = grub_strtoull(args[2], NULL, 10);
6082
6083 vtoy_dummy_menuentry(cmd, pos, len, "Boot in normal mode", "second_normal"); seldata[n++] = 1;
6084
6085 if (grub_strcmp(args[1], "Unix") != 0)
6086 {
6087 if (grub_strcmp(args[1], "Windows") == 0)
6088 {
6089 vtoy_dummy_menuentry(cmd, pos, len, "Boot in wimboot mode", "second_wimboot"); seldata[n++] = 2;
6090 }
6091 else
6092 {
6093 vtoy_dummy_menuentry(cmd, pos, len, "Boot in grub2 mode", "second_grub2"); seldata[n++] = 3;
6094 }
6095
6096 if (fsize <= VTOY_SIZE_1GB)
6097 {
6098 vtoy_dummy_menuentry(cmd, pos, len, "Boot in memdisk mode", "second_memdisk"); seldata[n++] = 4;
6099 }
6100 }
6101
6102 vtoy_dummy_menuentry(cmd, pos, len, "File checksum", "second_checksum"); seldata[n++] = 5;
6103
6104 do {
6105 g_ventoy_menu_esc = 1;
6106 g_ventoy_suppress_esc = 1;
6107 g_ventoy_suppress_esc_default = 0;
6108 g_ventoy_secondary_menu_on = 1;
6109 grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos);
6110 grub_script_execute_sourcecode(cfgfile);
6111 g_ventoy_menu_esc = 0;
6112 g_ventoy_suppress_esc = 0;
6113 g_ventoy_suppress_esc_default = 1;
6114 g_ventoy_secondary_menu_on = 0;
6115
6116 select = seldata[g_ventoy_last_entry];
6117
6118 if (select == 2)
6119 {
6120 g_ventoy_wimboot_mode = 1;
6121 g_vtoy_secondary_need_recover = 1;
6122 }
6123 else if (select == 3)
6124 {
6125 g_ventoy_grub2_mode = 1;
6126 g_vtoy_secondary_need_recover = 2;
6127 }
6128 else if (select == 4)
6129 {
6130 g_ventoy_memdisk_mode = 1;
6131 g_vtoy_secondary_need_recover = 3;
6132 }
6133 else if (select == 5)
6134 {
6135 grub_env_set("VTOY_CHKSUM_FILE_PATH", args[0]);
6136 grub_script_execute_sourcecode("configfile $vtoy_efi_part/grub/checksum.cfg");
6137 }
6138 }while (select == 5);
6139
6140 grub_free(cmd);
6141 return 0;
6142 }
6143
6144 static grub_err_t ventoy_cmd_secondary_recover_mode(grub_extcmd_context_t ctxt, int argc, char **args)
6145 {
6146 (void)ctxt;
6147 (void)argc;
6148 (void)args;
6149
6150 if (g_vtoy_secondary_need_recover == 1)
6151 {
6152 g_ventoy_wimboot_mode = 0;
6153 }
6154 else if (g_vtoy_secondary_need_recover == 2)
6155 {
6156 g_ventoy_grub2_mode = 0;
6157 }
6158 else if (g_vtoy_secondary_need_recover == 3)
6159 {
6160 g_ventoy_memdisk_mode = 0;
6161 }
6162
6163 g_vtoy_secondary_need_recover = 0;
6164
6165 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6166 }
6167
6168 static grub_err_t ventoy_cmd_fs_ignore_case(grub_extcmd_context_t ctxt, int argc, char **args)
6169 {
6170 (void)ctxt;
6171 (void)argc;
6172
6173 if (args[0][0] == '0')
6174 {
6175 g_ventoy_case_insensitive = 0;
6176 }
6177 else
6178 {
6179 g_ventoy_case_insensitive = 1;
6180 }
6181
6182 return 0;
6183 }
6184
6185 int ventoy_env_init(void)
6186 {
6187 int i;
6188 char buf[64];
6189
6190 grub_env_set("vtdebug_flag", "");
6191
6192 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
6193 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6194 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6195 for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++)
6196 {
6197 g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size);
6198 }
6199
6200 ventoy_filt_register(0, ventoy_wrapper_open);
6201
6202 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
6203 if (g_grub_param)
6204 {
6205 g_grub_param->grub_env_get = grub_env_get;
6206 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
6207 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
6208 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
6209 grub_env_set("env_param", buf);
6210 grub_env_set("ventoy_env_param", buf);
6211
6212 grub_env_export("env_param");
6213 grub_env_export("ventoy_env_param");
6214 }
6215
6216 grub_env_export("vtoy_winpeshl_ini_addr");
6217 grub_env_export("vtoy_winpeshl_ini_size");
6218
6219 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
6220 grub_env_set("vtoy_chain_file_size", buf);
6221 grub_env_export("vtoy_chain_file_size");
6222
6223 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
6224 grub_env_set("vtoy_chain_file_read", buf);
6225 grub_env_export("vtoy_chain_file_read");
6226
6227 return 0;
6228 }
6229
6230
6231
6232 static cmd_para ventoy_cmds[] =
6233 {
6234 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
6235 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
6236 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
6237 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
6238 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
6239 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
6240 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
6241 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6242 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6243 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
6244 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
6245 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
6246 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
6247 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
6248 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
6249 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
6250 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
6251 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
6252 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
6253 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
6254 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
6255 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
6256 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
6257 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
6258 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
6259 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
6260 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
6261
6262 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
6263 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
6264 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
6265 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
6266 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
6267 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
6268 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
6269
6270 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
6271 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
6272 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
6273 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
6274 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
6275 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
6276 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
6277 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
6278 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
6279 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
6280
6281
6282 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
6283 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
6284 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
6285 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
6286 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
6287 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
6288 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
6289 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
6290 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
6291 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
6292 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
6293
6294 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
6295 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
6296 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
6297 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
6298 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
6299 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
6300 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
6301
6302 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6303 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6304 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
6305 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
6306 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
6307 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
6308 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
6309 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
6310 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
6311 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
6312
6313 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
6314 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
6315 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
6316 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
6317 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
6318 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
6319 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
6320 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
6321 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
6322
6323 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
6324 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
6325 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
6326 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
6327
6328
6329 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
6330 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
6331 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
6332
6333 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
6334 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
6335 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
6336
6337
6338 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
6339 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
6340 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
6341 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
6342 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
6343 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
6344 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
6345 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
6346 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
6347 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
6348 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
6349 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
6350 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
6351 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
6352
6353 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
6354 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
6355 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
6356 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
6357 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
6358 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
6359 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
6360 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
6361 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
6362 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
6363 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
6364 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
6365
6366 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
6367 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
6368 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
6369 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
6370 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
6371 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
6372 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
6373 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
6374 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
6375 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
6376 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
6377 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
6378 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
6379 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
6380 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
6381 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
6382 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
6383 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
6384 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
6385 { "vt_is_standard_winiso", ventoy_cmd_is_standard_winiso, 0, NULL, "", "", NULL },
6386 { "vt_sel_winpe_wim", ventoy_cmd_sel_winpe_wim, 0, NULL, "", "", NULL },
6387 { "vt_need_secondary_menu", ventoy_cmd_need_secondary_menu, 0, NULL, "", "", NULL },
6388 { "vt_show_secondary_menu", ventoy_cmd_show_secondary_menu, 0, NULL, "", "", NULL },
6389 { "vt_fs_ignore_case", ventoy_cmd_fs_ignore_case, 0, NULL, "", "", NULL },
6390 { "vt_systemd_menu", ventoy_cmd_linux_systemd_menu, 0, NULL, "", "", NULL },
6391 { "vt_secondary_recover_mode", ventoy_cmd_secondary_recover_mode, 0, NULL, "", "", NULL },
6392 };
6393
6394 int ventoy_register_all_cmd(void)
6395 {
6396 grub_uint32_t i;
6397 cmd_para *cur = NULL;
6398
6399 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6400 {
6401 cur = ventoy_cmds + i;
6402 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
6403 cur->summary, cur->description, cur->parser);
6404 }
6405
6406 return 0;
6407 }
6408
6409 int ventoy_unregister_all_cmd(void)
6410 {
6411 grub_uint32_t i;
6412
6413 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6414 {
6415 grub_unregister_extcmd(ventoy_cmds[i].cmd);
6416 }
6417
6418 return 0;
6419 }
6420
6421