]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
113050c656f7f60f37bcc774ad3a64319b90ff0d
[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 int ventoy_check_password(const vtoy_password *pwd, int retry)
2187 {
2188 int offset;
2189 char input[256];
2190 grub_uint8_t md5[16];
2191
2192 while (retry--)
2193 {
2194 grub_memset(input, 0, sizeof(input));
2195
2196 grub_printf("Enter password: ");
2197 grub_refresh();
2198
2199 if (pwd->type == VTOY_PASSWORD_TXT)
2200 {
2201 grub_password_get(input, 128);
2202 if (grub_strcmp(pwd->text, input) == 0)
2203 {
2204 return 0;
2205 }
2206 }
2207 else if (pwd->type == VTOY_PASSWORD_MD5)
2208 {
2209 grub_password_get(input, 128);
2210 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2211 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2212 {
2213 return 0;
2214 }
2215 }
2216 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
2217 {
2218 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
2219 grub_password_get(input + offset, 128);
2220
2221 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2222 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2223 {
2224 return 0;
2225 }
2226 }
2227
2228 grub_printf("Invalid password!\n\n");
2229 grub_refresh();
2230 }
2231
2232 return 1;
2233 }
2234
2235 static img_info * ventoy_get_min_iso(img_iterator_node *node)
2236 {
2237 img_info *minimg = NULL;
2238 img_info *img = (img_info *)(node->firstiso);
2239
2240 while (img && (img_iterator_node *)(img->parent) == node)
2241 {
2242 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
2243 {
2244 minimg = img;
2245 }
2246 img = img->next;
2247 }
2248
2249 if (minimg)
2250 {
2251 minimg->select = 1;
2252 }
2253
2254 return minimg;
2255 }
2256
2257 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
2258 {
2259 img_iterator_node *Minchild = NULL;
2260 img_iterator_node *child = node->firstchild;
2261
2262 while (child && child->parent == node)
2263 {
2264 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
2265 {
2266 Minchild = child;
2267 }
2268 child = child->next;
2269 }
2270
2271 if (Minchild)
2272 {
2273 Minchild->select = 1;
2274 }
2275
2276 return Minchild;
2277 }
2278
2279 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
2280 {
2281 int offset = 1;
2282 img_info *img = NULL;
2283 const char *dir_class = NULL;
2284 const char *dir_alias = NULL;
2285 img_iterator_node *child = NULL;
2286 const menu_tip *tip = NULL;
2287
2288 if (node->isocnt == 0 || node->done == 1)
2289 {
2290 return 0;
2291 }
2292
2293 if (node->parent && node->parent->dirlen < node->dirlen)
2294 {
2295 offset = node->parent->dirlen;
2296 }
2297
2298 if (node == &g_img_iterator_head)
2299 {
2300 if (g_default_menu_mode == 0)
2301 {
2302 if (g_tree_view_menu_style == 0)
2303 {
2304 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2305 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2306 " echo 'return ...' \n"
2307 "}\n", "<--");
2308 }
2309 else
2310 {
2311 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2312 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2313 " echo 'return ...' \n"
2314 "}\n");
2315 }
2316 }
2317
2318 g_tree_script_pre = g_tree_script_pos;
2319 }
2320 else
2321 {
2322 node->dir[node->dirlen - 1] = 0;
2323 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2324 if (!dir_class)
2325 {
2326 dir_class = "vtoydir";
2327 }
2328
2329 tip = ventoy_plugin_get_menu_tip(vtoy_tip_directory, node->dir);
2330
2331 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2332 if (dir_alias)
2333 {
2334 if (g_tree_view_menu_style == 0)
2335 {
2336 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2337 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2338 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2339 }
2340 else
2341 {
2342 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2343 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2344 dir_alias, dir_class, node->dir + offset, tip);
2345 }
2346 }
2347 else
2348 {
2349 dir_alias = node->dir + offset;
2350
2351 if (g_tree_view_menu_style == 0)
2352 {
2353 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2354 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2355 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2356 }
2357 else
2358 {
2359 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2360 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2361 dir_alias, dir_class, node->dir + offset, tip);
2362 }
2363 }
2364
2365 if (g_tree_view_menu_style == 0)
2366 {
2367 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2368 "menuentry \"%-10s [%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2369 " echo 'return ...' \n"
2370 "}\n", "<--", node->dir);
2371 }
2372 else
2373 {
2374 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2375 "menuentry \"[%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2376 " echo 'return ...' \n"
2377 "}\n", node->dir);
2378 }
2379 }
2380
2381 while ((child = ventoy_get_min_child(node)) != NULL)
2382 {
2383 ventoy_dynamic_tree_menu(child);
2384 }
2385
2386 while ((img = ventoy_get_min_iso(node)) != NULL)
2387 {
2388 if (g_tree_view_menu_style == 0)
2389 {
2390 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2391 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2392 " %s_%s \n"
2393 "}\n",
2394 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2395 img->unsupport ? "[***********] " : "",
2396 img->alias ? img->alias : img->name, img->class, img,
2397 img->menu_prefix,
2398 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2399 }
2400 else
2401 {
2402 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2403 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2404 " %s_%s \n"
2405 "}\n",
2406 img->unsupport ? "[***********] " : "",
2407 img->alias ? img->alias : img->name, img->class, img,
2408 img->menu_prefix,
2409 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2410 }
2411 }
2412
2413 if (node != &g_img_iterator_head)
2414 {
2415 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "}\n");
2416 }
2417
2418 node->done = 1;
2419 return 0;
2420 }
2421
2422 static int ventoy_set_default_menu(void)
2423 {
2424 int img_len = 0;
2425 char *pos = NULL;
2426 char *end = NULL;
2427 char *def = NULL;
2428 const char *strdata = NULL;
2429 img_info *cur = NULL;
2430 img_info *default_node = NULL;
2431 const char *default_image = NULL;
2432
2433 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2434 if (default_image && default_image[0] == '/')
2435 {
2436 img_len = grub_strlen(default_image);
2437
2438 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2439 {
2440 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2441 {
2442 default_node = cur;
2443 break;
2444 }
2445 }
2446
2447 if (!default_node)
2448 {
2449 return 1;
2450 }
2451
2452 if (0 == g_default_menu_mode)
2453 {
2454 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2455 }
2456 else
2457 {
2458 def = grub_strdup(default_image);
2459 if (!def)
2460 {
2461 return 1;
2462 }
2463
2464 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2465
2466 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2467 if (strdata && strdata[0] == '/')
2468 {
2469 pos = def + grub_strlen(strdata);
2470 if (*pos == '/')
2471 {
2472 pos++;
2473 }
2474 }
2475 else
2476 {
2477 pos = def + 1;
2478 }
2479
2480 while ((end = grub_strchr(pos, '/')) != NULL)
2481 {
2482 *end = 0;
2483 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2484 pos = end + 1;
2485 }
2486
2487 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2488 grub_free(def);
2489 }
2490 }
2491
2492 return 0;
2493 }
2494
2495 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2496 {
2497 img_info *next = NULL;
2498 img_info *cur = g_ventoy_img_list;
2499
2500 (void)ctxt;
2501 (void)argc;
2502 (void)args;
2503
2504 while (cur)
2505 {
2506 next = cur->next;
2507 grub_free(cur);
2508 cur = next;
2509 }
2510
2511 g_ventoy_img_list = NULL;
2512 g_ventoy_img_count = 0;
2513
2514 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2515 }
2516
2517 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2518 {
2519 long img_id = 0;
2520 img_info *cur = g_ventoy_img_list;
2521
2522 (void)ctxt;
2523
2524 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2525 {
2526 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2527 }
2528
2529 img_id = grub_strtol(args[0], NULL, 10);
2530 if (img_id >= g_ventoy_img_count)
2531 {
2532 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2533 }
2534
2535 debug("Find image %ld name \n", img_id);
2536
2537 while (cur && img_id > 0)
2538 {
2539 img_id--;
2540 cur = cur->next;
2541 }
2542
2543 if (!cur)
2544 {
2545 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2546 }
2547
2548 debug("image name is %s\n", cur->name);
2549
2550 grub_env_set(args[1], cur->name);
2551
2552 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2553 }
2554
2555 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2556 {
2557 int len = 0;
2558 char id[32] = {0};
2559 img_info *cur = g_ventoy_img_list;
2560
2561 (void)ctxt;
2562
2563 if (argc != 1)
2564 {
2565 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2566 }
2567
2568 len = (int)grub_strlen(args[0]);
2569
2570 while (cur)
2571 {
2572 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2573 {
2574 break;
2575 }
2576 cur = cur->next;
2577 }
2578
2579 if (!cur)
2580 {
2581 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2582 }
2583
2584 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2585 grub_env_set("chosen", id);
2586 grub_env_export("chosen");
2587
2588 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2589 }
2590
2591 static char g_fake_vlnk_src[512];
2592 static char g_fake_vlnk_dst[512];
2593 static grub_uint64_t g_fake_vlnk_size;
2594 static grub_err_t ventoy_cmd_set_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2595 {
2596 (void)ctxt;
2597 (void)argc;
2598 (void)args;
2599
2600 g_fake_vlnk_size = (grub_uint64_t)grub_strtoull(args[2], NULL, 10);
2601
2602 grub_strncpy(g_fake_vlnk_dst, args[0], sizeof(g_fake_vlnk_dst));
2603 grub_snprintf(g_fake_vlnk_src, sizeof(g_fake_vlnk_src), "%s/________VENTOYVLNK.vlnk.%s", g_iso_path, args[1]);
2604
2605 grub_file_vtoy_vlnk(g_fake_vlnk_src, g_fake_vlnk_dst);
2606
2607 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2608 }
2609
2610 static grub_err_t ventoy_cmd_reset_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2611 {
2612 (void)ctxt;
2613 (void)argc;
2614 (void)args;
2615
2616 g_fake_vlnk_src[0] = 0;
2617 g_fake_vlnk_dst[0] = 0;
2618 g_fake_vlnk_size = 0;
2619 grub_file_vtoy_vlnk(NULL, NULL);
2620
2621 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2622 }
2623
2624
2625 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2626 {
2627 char value[32];
2628 char *pos = NULL;
2629 char *last = NULL;
2630 const char *id = NULL;
2631 img_info *cur = NULL;
2632
2633 (void)ctxt;
2634
2635 if (argc < 1 || argc > 3)
2636 {
2637 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2638 }
2639
2640 if (g_fake_vlnk_src[0] && g_fake_vlnk_dst[0])
2641 {
2642 pos = grub_strchr(g_fake_vlnk_src, '/');
2643 grub_env_set(args[0], pos);
2644 if (argc > 1)
2645 {
2646 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(g_fake_vlnk_size));
2647 grub_env_set(args[1], value);
2648 }
2649
2650 if (argc > 2)
2651 {
2652 for (last = pos; *pos; pos++)
2653 {
2654 if (*pos == '/')
2655 {
2656 last = pos;
2657 }
2658 }
2659 grub_env_set(args[2], last + 1);
2660 }
2661
2662 goto end;
2663 }
2664
2665 id = grub_env_get("chosen");
2666
2667 pos = grub_strstr(id, "VID_");
2668 if (pos)
2669 {
2670 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2671 }
2672 else
2673 {
2674 cur = g_ventoy_img_list;
2675 }
2676
2677 if (!cur)
2678 {
2679 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2680 }
2681
2682 grub_env_set(args[0], cur->path);
2683
2684 if (argc > 1)
2685 {
2686 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2687 grub_env_set(args[1], value);
2688 }
2689
2690 if (argc > 2)
2691 {
2692 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2693 grub_env_set(args[2], cur->name);
2694 }
2695
2696 end:
2697 g_svd_replace_offset = 0;
2698
2699 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2700 }
2701
2702
2703 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2704 {
2705 int len;
2706 grub_fs_t fs;
2707 grub_device_t dev = NULL;
2708 img_info *cur = NULL;
2709 img_info *tail = NULL;
2710 img_info *min = NULL;
2711 img_info *head = NULL;
2712 const char *strdata = NULL;
2713 char *device_name = NULL;
2714 char buf[32];
2715 img_iterator_node *node = NULL;
2716 img_iterator_node *tmp = NULL;
2717
2718 (void)ctxt;
2719
2720 if (argc != 2)
2721 {
2722 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2723 }
2724
2725 if (g_ventoy_img_list || g_ventoy_img_count)
2726 {
2727 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2728 }
2729
2730 VTOY_CMD_CHECK(1);
2731
2732 g_enumerate_time_checked = 0;
2733 g_enumerate_start_time_ms = grub_get_time_ms();
2734
2735 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2736 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2737 {
2738 g_filt_dot_underscore_file = 1;
2739 }
2740
2741 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2742 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2743 {
2744 g_sort_case_sensitive = 1;
2745 }
2746
2747 device_name = grub_file_get_device_name(args[0]);
2748 if (!device_name)
2749 {
2750 goto fail;
2751 }
2752
2753 g_enum_dev = dev = grub_device_open(device_name);
2754 if (!dev)
2755 {
2756 goto fail;
2757 }
2758
2759 g_enum_fs = fs = grub_fs_probe(dev);
2760 if (!fs)
2761 {
2762 goto fail;
2763 }
2764
2765 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2766 {
2767 debug("unsupported fs:<%s>\n", fs->name);
2768 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2769 goto fail;
2770 }
2771
2772 ventoy_set_env("vtoy_iso_fs", fs->name);
2773
2774 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2775 if (strdata && strdata[0] == '1')
2776 {
2777 g_default_menu_mode = 1;
2778 }
2779
2780 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2781
2782 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2783
2784 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2785 if (strdata && strdata[0] == '/')
2786 {
2787 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2788 if (g_img_iterator_head.dir[len - 1] != '/')
2789 {
2790 g_img_iterator_head.dir[len++] = '/';
2791 }
2792 g_img_iterator_head.dirlen = len;
2793 }
2794 else
2795 {
2796 g_img_iterator_head.dirlen = 1;
2797 grub_strcpy(g_img_iterator_head.dir, "/");
2798 }
2799
2800 g_img_iterator_head.tail = &tail;
2801
2802 if (g_img_max_search_level < 0)
2803 {
2804 g_img_max_search_level = GRUB_INT_MAX;
2805 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2806 if (strdata && ventoy_is_decimal(strdata))
2807 {
2808 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2809 }
2810 }
2811
2812 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2813 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2814 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2815 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2816 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2817 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2818
2819 for (node = &g_img_iterator_head; node; node = node->next)
2820 {
2821 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2822 }
2823
2824 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2825 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2826 {
2827 g_tree_view_menu_style = 1;
2828 }
2829
2830 ventoy_set_default_menu();
2831
2832 for (node = &g_img_iterator_head; node; node = node->next)
2833 {
2834 ventoy_dynamic_tree_menu(node);
2835 }
2836
2837 /* free node */
2838 node = g_img_iterator_head.next;
2839 while (node)
2840 {
2841 tmp = node->next;
2842 grub_free(node);
2843 node = tmp;
2844 }
2845
2846 /* sort image list by image name */
2847 while (g_ventoy_img_list)
2848 {
2849 min = g_ventoy_img_list;
2850 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2851 {
2852 if (ventoy_cmp_img(min, cur) > 0)
2853 {
2854 min = cur;
2855 }
2856 }
2857
2858 if (min->prev)
2859 {
2860 min->prev->next = min->next;
2861 }
2862
2863 if (min->next)
2864 {
2865 min->next->prev = min->prev;
2866 }
2867
2868 if (min == g_ventoy_img_list)
2869 {
2870 g_ventoy_img_list = min->next;
2871 }
2872
2873 if (head == NULL)
2874 {
2875 head = tail = min;
2876 min->prev = NULL;
2877 min->next = NULL;
2878 }
2879 else
2880 {
2881 tail->next = min;
2882 min->prev = tail;
2883 min->next = NULL;
2884 tail = min;
2885 }
2886 }
2887
2888 g_ventoy_img_list = head;
2889
2890 if (g_default_menu_mode == 1)
2891 {
2892 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2893 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2894 " echo 'return ...' \n"
2895 "}\n", "<--");
2896 }
2897
2898 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2899 {
2900 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2901 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2902 " %s_%s \n"
2903 "}\n",
2904 cur->unsupport ? "[***********] " : "",
2905 cur->alias ? cur->alias : cur->name, cur->class, cur,
2906 cur->menu_prefix,
2907 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2908 }
2909
2910 g_tree_script_buf[g_tree_script_pos] = 0;
2911 g_list_script_buf[g_list_script_pos] = 0;
2912
2913 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2914 grub_env_set(args[1], buf);
2915
2916 fail:
2917
2918 check_free(device_name, grub_free);
2919 check_free(dev, grub_device_close);
2920
2921 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2922 }
2923
2924 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2925 {
2926 grub_disk_t disk;
2927 char *device_name;
2928 char *pos;
2929 char *pos2;
2930
2931 device_name = grub_file_get_device_name(filename);
2932 if (!device_name)
2933 {
2934 return 1;
2935 }
2936
2937 pos = device_name;
2938 if (pos[0] == '(')
2939 {
2940 pos++;
2941 }
2942
2943 pos2 = grub_strstr(pos, ",");
2944 if (!pos2)
2945 {
2946 pos2 = grub_strstr(pos, ")");
2947 }
2948
2949 if (pos2)
2950 {
2951 *pos2 = 0;
2952 }
2953
2954 disk = grub_disk_open(pos);
2955 if (disk)
2956 {
2957 grub_disk_read(disk, 0, 0x180, 16, guid);
2958 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2959 grub_disk_close(disk);
2960 }
2961 else
2962 {
2963 return 1;
2964 }
2965
2966 grub_free(device_name);
2967 return 0;
2968 }
2969
2970 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2971 {
2972 eltorito_descriptor desc;
2973
2974 grub_memset(&desc, 0, sizeof(desc));
2975 grub_file_seek(file, 17 * 2048);
2976 grub_file_read(file, &desc, sizeof(desc));
2977
2978 if (desc.type != 0 || desc.version != 1)
2979 {
2980 return 0;
2981 }
2982
2983 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2984 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2985 {
2986 return 0;
2987 }
2988
2989 return desc.sector;
2990 }
2991
2992 static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector)
2993 {
2994 grub_uint8_t buf[512];
2995
2996 grub_file_seek(file, sector * 2048);
2997 grub_file_read(file, buf, sizeof(buf));
2998
2999 if (buf[0] == 0x01 && buf[1] == 0x00 &&
3000 buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88)
3001 {
3002 return *((grub_uint32_t *)(buf + 40));
3003 }
3004
3005 return 0;
3006 }
3007
3008 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
3009 {
3010 int i;
3011 int x86count = 0;
3012 grub_uint8_t buf[512];
3013 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
3014
3015 grub_file_seek(file, sector * 2048);
3016 grub_file_read(file, buf, sizeof(buf));
3017
3018 if (buf[0] == 0x01 && buf[1] == 0xEF)
3019 {
3020 debug("%s efi eltorito in Validation Entry\n", file->name);
3021 return 1;
3022 }
3023
3024 if (buf[0] == 0x01 && buf[1] == 0x00)
3025 {
3026 x86count++;
3027 }
3028
3029 for (i = 64; i < (int)sizeof(buf); i += 32)
3030 {
3031 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
3032 {
3033 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3034 return 1;
3035 }
3036
3037 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
3038 {
3039 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3040 return 1;
3041 }
3042 }
3043
3044 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
3045 {
3046 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
3047 {
3048 if (buf[36] == parttype[i])
3049 {
3050 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
3051 return 1;
3052 }
3053 }
3054 }
3055
3056 debug("%s does not contain efi eltorito\n", file->name);
3057 return 0;
3058 }
3059
3060 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
3061 {
3062 char *pos;
3063 const char *fs = NULL;
3064 const char *val = NULL;
3065 const char *cdprompt = NULL;
3066 grub_uint32_t i;
3067 grub_uint8_t chksum = 0;
3068 grub_disk_t disk;
3069
3070 disk = file->device->disk;
3071 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
3072
3073 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
3074 param->vtoy_disk_part_id = disk->partition->number + 1;
3075 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
3076
3077 pos = grub_strstr(file->name, "/");
3078 if (!pos)
3079 {
3080 pos = file->name;
3081 }
3082
3083 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
3084
3085 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
3086
3087 param->vtoy_img_size = file->size;
3088
3089 param->vtoy_reserved[0] = g_ventoy_break_level;
3090 param->vtoy_reserved[1] = g_ventoy_debug_level;
3091
3092 param->vtoy_reserved[2] = g_ventoy_chain_type;
3093
3094 /* Windows CD/DVD prompt 0:suppress 1:reserved */
3095 param->vtoy_reserved[4] = 0;
3096 if (g_ventoy_chain_type == 1) /* Windows */
3097 {
3098 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
3099 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
3100 {
3101 param->vtoy_reserved[4] = 1;
3102 }
3103 }
3104
3105 fs = ventoy_get_env("ventoy_fs_probe");
3106 if (fs && grub_strcmp(fs, "udf") == 0)
3107 {
3108 param->vtoy_reserved[3] = 1;
3109 }
3110
3111 param->vtoy_reserved[5] = 0;
3112 val = ventoy_get_env("VTOY_LINUX_REMOUNT");
3113 if (val && val[0] == '1' && val[1] == 0)
3114 {
3115 param->vtoy_reserved[5] = 1;
3116 }
3117
3118 /* ventoy_disk_signature used for vlnk */
3119 param->vtoy_reserved[6] = file->vlnk;
3120 grub_memcpy(param->vtoy_reserved + 7, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
3121
3122 /* calculate checksum */
3123 for (i = 0; i < sizeof(ventoy_os_param); i++)
3124 {
3125 chksum += *((grub_uint8_t *)param + i);
3126 }
3127 param->chksum = (grub_uint8_t)(0x100 - chksum);
3128
3129 return;
3130 }
3131
3132 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3133 {
3134 grub_uint32_t i = 0;
3135 grub_uint64_t total = 0;
3136 grub_uint64_t fileblk = 0;
3137 ventoy_img_chunk *chunk = NULL;
3138
3139 for (i = 0; i < chunklist->cur_chunk; i++)
3140 {
3141 chunk = chunklist->chunk + i;
3142
3143 if (chunk->disk_start_sector <= start)
3144 {
3145 debug("%u disk start invalid %lu\n", i, (ulong)start);
3146 return 1;
3147 }
3148
3149 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
3150 }
3151
3152 fileblk = (file->size + 511) / 512;
3153
3154 if (total != fileblk)
3155 {
3156 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
3157 if ((file->size % 512) && (total + 1 == fileblk))
3158 {
3159 debug("maybe img file to be processed.\n");
3160 return 0;
3161 }
3162
3163 return 1;
3164 }
3165
3166 return 0;
3167 }
3168
3169 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3170 {
3171 int fs_type;
3172 int len;
3173 grub_uint32_t i = 0;
3174 grub_uint32_t sector = 0;
3175 grub_uint32_t count = 0;
3176 grub_off_t size = 0;
3177 grub_off_t read = 0;
3178
3179 fs_type = ventoy_get_fs_type(file->fs->name);
3180 if (fs_type == ventoy_fs_exfat)
3181 {
3182 grub_fat_get_file_chunk(start, file, chunklist);
3183 }
3184 else if (fs_type == ventoy_fs_ext)
3185 {
3186 grub_ext_get_file_chunk(start, file, chunklist);
3187 }
3188 else
3189 {
3190 file->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read;
3191 file->read_hook_data = chunklist;
3192
3193 for (size = file->size; size > 0; size -= read)
3194 {
3195 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
3196 grub_file_read(file, NULL, read);
3197 }
3198
3199 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
3200 {
3201 chunklist->chunk[i].disk_start_sector += start;
3202 chunklist->chunk[i].disk_end_sector += start;
3203 }
3204
3205 if (ventoy_fs_udf == fs_type)
3206 {
3207 for (i = 0; i < chunklist->cur_chunk; i++)
3208 {
3209 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
3210 chunklist->chunk[i].img_start_sector = sector;
3211 chunklist->chunk[i].img_end_sector = sector + count - 1;
3212 sector += count;
3213 }
3214 }
3215 }
3216
3217 len = (int)grub_strlen(file->name);
3218 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
3219 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
3220 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
3221 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
3222 {
3223 for (i = 0; i < chunklist->cur_chunk; i++)
3224 {
3225 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
3226 if (count < 4)
3227 {
3228 count = 1;
3229 }
3230 else
3231 {
3232 count >>= 2;
3233 }
3234
3235 chunklist->chunk[i].img_start_sector = sector;
3236 chunklist->chunk[i].img_end_sector = sector + count - 1;
3237 sector += count;
3238 }
3239 }
3240
3241 return 0;
3242 }
3243
3244 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3245 {
3246 int rc;
3247 grub_file_t file;
3248 grub_disk_addr_t start;
3249
3250 (void)ctxt;
3251 (void)argc;
3252
3253 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3254 if (!file)
3255 {
3256 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3257 }
3258
3259 g_conf_replace_count = 0;
3260 grub_memset(g_conf_replace_node, 0, sizeof(g_conf_replace_node ));
3261 grub_memset(g_conf_replace_offset, 0, sizeof(g_conf_replace_offset ));
3262
3263 if (g_img_chunk_list.chunk)
3264 {
3265 grub_free(g_img_chunk_list.chunk);
3266 }
3267
3268 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
3269 {
3270 grub_file_close(file);
3271 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
3272 }
3273
3274 /* get image chunk data */
3275 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
3276 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3277 if (NULL == g_img_chunk_list.chunk)
3278 {
3279 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3280 }
3281
3282 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
3283 g_img_chunk_list.cur_chunk = 0;
3284
3285 start = file->device->disk->partition->start;
3286
3287 ventoy_get_block_list(file, &g_img_chunk_list, start);
3288
3289 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
3290 grub_file_close(file);
3291
3292 if (rc)
3293 {
3294 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
3295 }
3296
3297 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
3298 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
3299 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3300 }
3301
3302 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
3303 {
3304 int i;
3305 int n;
3306 grub_uint64_t offset = 0;
3307 grub_uint32_t align = 0;
3308 grub_file_t file = NULL;
3309 conf_replace *node = NULL;
3310 conf_replace *nodes[VTOY_MAX_CONF_REPLACE] = { NULL };
3311 ventoy_grub_param_file_replace *replace = NULL;
3312
3313 (void)ctxt;
3314 (void)argc;
3315 (void)args;
3316
3317 debug("select conf replace argc:%d\n", argc);
3318
3319 if (argc < 2)
3320 {
3321 return 0;
3322 }
3323
3324 n = ventoy_plugin_find_conf_replace(args[1], nodes);
3325 if (!n)
3326 {
3327 debug("Conf replace not found for %s\n", args[1]);
3328 goto end;
3329 }
3330
3331 debug("Find %d conf replace for %s\n", n, args[1]);
3332
3333 g_conf_replace_count = n;
3334 for (i = 0; i < n; i++)
3335 {
3336 node = nodes[i];
3337
3338 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3339 if (file)
3340 {
3341 offset = grub_iso9660_get_last_file_dirent_pos(file);
3342 grub_file_close(file);
3343 }
3344 else if (node->img > 0)
3345 {
3346 offset = 0;
3347 }
3348 else
3349 {
3350 debug("<(loop)%s> NOT exist\n", node->orgconf);
3351 continue;
3352 }
3353
3354 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3355 if (!file)
3356 {
3357 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3358 continue;
3359 }
3360
3361 align = ((int)file->size + 2047) / 2048 * 2048;
3362
3363 if (align > vtoy_max_replace_file_size)
3364 {
3365 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3366 grub_file_close(file);
3367 continue;
3368 }
3369
3370 grub_file_read(file, g_conf_replace_new_buf[i], file->size);
3371 grub_file_close(file);
3372 g_conf_replace_new_len[i] = (int)file->size;
3373 g_conf_replace_new_len_align[i] = align;
3374
3375 g_conf_replace_node[i] = node;
3376 g_conf_replace_offset[i] = offset + 2;
3377
3378 if (node->img > 0)
3379 {
3380 replace = &(g_grub_param->img_replace[i]);
3381 replace->magic = GRUB_IMG_REPLACE_MAGIC;
3382 grub_snprintf(replace->old_file_name[replace->old_name_cnt], 256, "%s", node->orgconf);
3383 replace->old_name_cnt++;
3384 }
3385
3386 debug("conf_replace OK: newlen[%d]: %d img:%d\n", i, g_conf_replace_new_len[i], node->img);
3387 }
3388
3389 end:
3390 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3391 }
3392
3393 static int ventoy_var_expand(int *record, int *flag, const char *var, char *expand, int len)
3394 {
3395 int i = 0;
3396 int n = 0;
3397 char c;
3398 const char *ch = var;
3399
3400 *record = 0;
3401 expand[0] = 0;
3402
3403 while (*ch)
3404 {
3405 if (*ch == '_' || (*ch >= '0' && *ch <= '9') || (*ch >= 'A' && *ch <= 'Z') || (*ch >= 'a' && *ch <= 'z'))
3406 {
3407 ch++;
3408 n++;
3409 }
3410 else
3411 {
3412 debug("Invalid variable letter <%c>\n", *ch);
3413 goto end;
3414 }
3415 }
3416
3417 if (n > 32)
3418 {
3419 debug("Invalid variable length:%d <%s>\n", n, var);
3420 goto end;
3421 }
3422
3423 if (grub_strncmp(var, "VT_", 3) == 0) /* built-in variables */
3424 {
3425
3426 }
3427 else
3428 {
3429 if (*flag == 0)
3430 {
3431 *flag = 1;
3432 grub_printf("\n=================== Variables Expansion ===================\n\n");
3433 }
3434
3435 grub_printf("<%s>: ", var);
3436 grub_refresh();
3437
3438 while (i < (len - 1))
3439 {
3440 c = grub_getkey();
3441 if ((c == '\n') || (c == '\r'))
3442 {
3443 if (i > 0)
3444 {
3445 grub_printf("\n");
3446 grub_refresh();
3447 *record = 1;
3448 break;
3449 }
3450 }
3451 else if (grub_isprint(c))
3452 {
3453 if (i + 1 < (len - 1))
3454 {
3455 grub_printf("%c", c);
3456 grub_refresh();
3457 expand[i++] = c;
3458 expand[i] = 0;
3459 }
3460 }
3461 else if (c == '\b')
3462 {
3463 if (i > 0)
3464 {
3465 expand[i - 1] = ' ';
3466 grub_printf("\r<%s>: %s", var, expand);
3467
3468 expand[i - 1] = 0;
3469 grub_printf("\r<%s>: %s", var, expand);
3470
3471 grub_refresh();
3472 i--;
3473 }
3474 }
3475 }
3476 }
3477
3478 end:
3479 if (expand[0] == 0)
3480 {
3481 grub_snprintf(expand, len, "$$%s$$", var);
3482 }
3483
3484 return 0;
3485 }
3486
3487 static int ventoy_auto_install_var_expand(install_template *node)
3488 {
3489 int pos = 0;
3490 int flag = 0;
3491 int record = 0;
3492 int newlen = 0;
3493 char *start = NULL;
3494 char *end = NULL;
3495 char *newbuf = NULL;
3496 char *curline = NULL;
3497 char *nextline = NULL;
3498 grub_uint8_t *code = NULL;
3499 char value[512];
3500 var_node *CurNode = NULL;
3501 var_node *pVarList = NULL;
3502
3503 code = (grub_uint8_t *)node->filebuf;
3504
3505 if (node->filelen >= VTOY_SIZE_1MB)
3506 {
3507 debug("auto install script too long %d\n", node->filelen);
3508 return 0;
3509 }
3510
3511 if ((code[0] == 0xff && code[1] == 0xfe) || (code[0] == 0xfe && code[1] == 0xff))
3512 {
3513 debug("UCS-2 encoding NOT supported\n");
3514 return 0;
3515 }
3516
3517 start = grub_strstr(node->filebuf, "$$");
3518 if (!start)
3519 {
3520 debug("no need to expand variable, no start.\n");
3521 return 0;
3522 }
3523
3524 end = grub_strstr(start + 2, "$$");
3525 if (!end)
3526 {
3527 debug("no need to expand variable, no end.\n");
3528 return 0;
3529 }
3530
3531 newlen = grub_max(node->filelen * 10, VTOY_SIZE_128KB);
3532 newbuf = grub_malloc(newlen);
3533 if (!newbuf)
3534 {
3535 debug("Failed to alloc newbuf %d\n", newlen);
3536 return 0;
3537 }
3538
3539 for (curline = node->filebuf; curline; curline = nextline)
3540 {
3541 nextline = ventoy_get_line(curline);
3542
3543 start = grub_strstr(curline, "$$");
3544 if (start)
3545 {
3546 end = grub_strstr(start + 2, "$$");
3547 }
3548
3549 if (start && end)
3550 {
3551 *start = *end = 0;
3552 VTOY_APPEND_NEWBUF(curline);
3553
3554 for (CurNode = pVarList; CurNode; CurNode = CurNode->next)
3555 {
3556 if (grub_strcmp(start + 2, CurNode->var) == 0)
3557 {
3558 grub_snprintf(value, sizeof(value) - 1, "%s", CurNode->val);
3559 break;
3560 }
3561 }
3562
3563 if (!CurNode)
3564 {
3565 value[sizeof(value) - 1] = 0;
3566 ventoy_var_expand(&record, &flag, start + 2, value, sizeof(value) - 1);
3567
3568 if (record)
3569 {
3570 CurNode = grub_zalloc(sizeof(var_node));
3571 if (CurNode)
3572 {
3573 grub_snprintf(CurNode->var, sizeof(CurNode->var), "%s", start + 2);
3574 grub_snprintf(CurNode->val, sizeof(CurNode->val), "%s", value);
3575 CurNode->next = pVarList;
3576 pVarList = CurNode;
3577 }
3578 }
3579 }
3580
3581 VTOY_APPEND_NEWBUF(value);
3582
3583 VTOY_APPEND_NEWBUF(end + 2);
3584 }
3585 else
3586 {
3587 VTOY_APPEND_NEWBUF(curline);
3588 }
3589
3590 if (pos > 0 && newbuf[pos - 1] == '\r')
3591 {
3592 newbuf[pos - 1] = '\n';
3593 }
3594 else
3595 {
3596 newbuf[pos++] = '\n';
3597 }
3598 }
3599
3600 grub_free(node->filebuf);
3601 node->filebuf = newbuf;
3602 node->filelen = pos;
3603
3604 while (pVarList)
3605 {
3606 CurNode = pVarList->next;
3607 grub_free(pVarList);
3608 pVarList = CurNode;
3609 }
3610
3611 return 0;
3612 }
3613
3614 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3615 {
3616 int i = 0;
3617 int pos = 0;
3618 int defidx = 1;
3619 char *buf = NULL;
3620 grub_file_t file = NULL;
3621 char configfile[128];
3622 install_template *node = NULL;
3623
3624 (void)ctxt;
3625 (void)argc;
3626 (void)args;
3627
3628 debug("select auto installation argc:%d\n", argc);
3629
3630 if (argc < 1)
3631 {
3632 return 0;
3633 }
3634
3635 node = ventoy_plugin_find_install_template(args[0]);
3636 if (!node)
3637 {
3638 debug("Auto install template not found for %s\n", args[0]);
3639 return 0;
3640 }
3641
3642 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3643 {
3644 defidx = node->autosel;
3645 if (node->timeout < 0)
3646 {
3647 node->cursel = node->autosel - 1;
3648 debug("Auto install template auto select %d\n", node->autosel);
3649 goto load;
3650 }
3651 }
3652
3653 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3654 if (!buf)
3655 {
3656 return 0;
3657 }
3658
3659 if (node->timeout > 0)
3660 {
3661 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3662 }
3663
3664 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" --class=\"sel_auto_install\" {\n"
3665 " echo %s\n}\n", "");
3666
3667 for (i = 0; i < node->templatenum; i++)
3668 {
3669 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" --class=\"sel_auto_install\" {\n"
3670 " echo \"\"\n}\n",
3671 node->templatepath[i].path);
3672 }
3673
3674 g_ventoy_menu_esc = 1;
3675 g_ventoy_suppress_esc = 1;
3676 g_ventoy_suppress_esc_default = defidx;
3677
3678 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3679 grub_script_execute_sourcecode(configfile);
3680
3681 g_ventoy_menu_esc = 0;
3682 g_ventoy_suppress_esc = 0;
3683 g_ventoy_suppress_esc_default = 1;
3684
3685 grub_free(buf);
3686
3687 node->cursel = g_ventoy_last_entry - 1;
3688
3689 load:
3690 grub_check_free(node->filebuf);
3691 node->filelen = 0;
3692
3693 if (node->cursel >= 0 && node->cursel < node->templatenum)
3694 {
3695 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"),
3696 node->templatepath[node->cursel].path);
3697 if (file)
3698 {
3699 node->filebuf = grub_malloc(file->size + 8);
3700 if (node->filebuf)
3701 {
3702 grub_file_read(file, node->filebuf, file->size);
3703 grub_file_close(file);
3704
3705 grub_memset(node->filebuf + file->size, 0, 8);
3706 node->filelen = (int)file->size;
3707
3708 ventoy_auto_install_var_expand(node);
3709 }
3710 }
3711 else
3712 {
3713 debug("Failed to open auto install script <%s%s>\n",
3714 ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path);
3715 }
3716 }
3717
3718 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3719 }
3720
3721 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3722 {
3723 int i = 0;
3724 int pos = 0;
3725 int defidx = 1;
3726 char *buf = NULL;
3727 char configfile[128];
3728 persistence_config *node;
3729
3730 (void)ctxt;
3731 (void)argc;
3732 (void)args;
3733
3734 debug("select persistence argc:%d\n", argc);
3735
3736 if (argc < 1)
3737 {
3738 return 0;
3739 }
3740
3741 node = ventoy_plugin_find_persistent(args[0]);
3742 if (!node)
3743 {
3744 debug("Persistence image not found for %s\n", args[0]);
3745 return 0;
3746 }
3747
3748 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3749 {
3750 defidx = node->autosel;
3751 if (node->timeout < 0)
3752 {
3753 node->cursel = node->autosel - 1;
3754 debug("Persistence image auto select %d\n", node->autosel);
3755 return 0;
3756 }
3757 }
3758
3759 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3760 if (!buf)
3761 {
3762 return 0;
3763 }
3764
3765 if (node->timeout > 0)
3766 {
3767 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3768 }
3769
3770 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" --class=\"sel_persistence\" {\n"
3771 " echo %s\n}\n", "");
3772
3773 for (i = 0; i < node->backendnum; i++)
3774 {
3775 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" --class=\"sel_persistence\" {\n"
3776 " echo \"\"\n}\n",
3777 node->backendpath[i].path);
3778
3779 }
3780
3781 g_ventoy_menu_esc = 1;
3782 g_ventoy_suppress_esc = 1;
3783 g_ventoy_suppress_esc_default = defidx;
3784
3785 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3786 grub_script_execute_sourcecode(configfile);
3787
3788 g_ventoy_menu_esc = 0;
3789 g_ventoy_suppress_esc = 0;
3790 g_ventoy_suppress_esc_default = 1;
3791
3792 grub_free(buf);
3793
3794 node->cursel = g_ventoy_last_entry - 1;
3795
3796 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3797 }
3798
3799 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3800 {
3801 grub_uint32_t i;
3802 ventoy_img_chunk *cur;
3803
3804 (void)ctxt;
3805 (void)argc;
3806 (void)args;
3807
3808 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3809 {
3810 cur = g_img_chunk_list.chunk + i;
3811 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3812 cur->img_start_sector, cur->img_end_sector,
3813 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3814 );
3815 }
3816
3817 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3818 }
3819
3820 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3821 {
3822 grub_uint32_t i;
3823 grub_file_t file;
3824 ventoy_img_chunk_list chunklist;
3825
3826 (void)ctxt;
3827 (void)argc;
3828
3829 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3830 if (!file)
3831 {
3832 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3833 }
3834
3835 /* get image chunk data */
3836 grub_memset(&chunklist, 0, sizeof(chunklist));
3837 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3838 if (NULL == chunklist.chunk)
3839 {
3840 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3841 }
3842
3843 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3844 chunklist.cur_chunk = 0;
3845
3846 ventoy_get_block_list(file, &chunklist, 0);
3847
3848 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3849 {
3850 grub_printf("########## UNSUPPORTED ###############\n");
3851 }
3852
3853 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3854
3855 for (i = 0; i < chunklist.cur_chunk; i++)
3856 {
3857 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3858 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3859 }
3860
3861 grub_printf("\n==================================\n");
3862
3863 for (i = 0; i < chunklist.cur_chunk; i++)
3864 {
3865 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3866 (ulonglong)chunklist.chunk[i].img_start_sector,
3867 (ulonglong)chunklist.chunk[i].img_end_sector,
3868 (ulonglong)chunklist.chunk[i].disk_start_sector,
3869 (ulonglong)chunklist.chunk[i].disk_end_sector
3870 );
3871 }
3872
3873 grub_free(chunklist.chunk);
3874 grub_file_close(file);
3875
3876 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3877 }
3878
3879 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3880 {
3881 int i;
3882 ventoy_grub_param_file_replace *replace = NULL;
3883
3884 (void)ctxt;
3885 (void)argc;
3886 (void)args;
3887
3888 if (argc >= 2)
3889 {
3890 replace = &(g_grub_param->file_replace);
3891 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3892
3893 replace->old_name_cnt = 0;
3894 for (i = 0; i < 4 && i + 1 < argc; i++)
3895 {
3896 replace->old_name_cnt++;
3897 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3898 }
3899
3900 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3901 }
3902
3903 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3904 }
3905
3906 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3907 {
3908 char buf[32];
3909 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3910
3911 (void)ctxt;
3912
3913 if (argc >= 1)
3914 {
3915 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3916 grub_env_set(args[0], buf);
3917 }
3918
3919 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3920 }
3921
3922 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3923 {
3924 (void)ctxt;
3925 (void)argc;
3926 (void)args;
3927
3928 if (argc == 0)
3929 {
3930 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3931 grub_printf("%s", g_list_script_buf);
3932 }
3933 else
3934 {
3935 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3936 grub_printf("%s", g_tree_script_buf);
3937 }
3938
3939 return 0;
3940 }
3941
3942 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3943 {
3944 img_info *cur = g_ventoy_img_list;
3945
3946 (void)ctxt;
3947 (void)argc;
3948 (void)args;
3949
3950 while (cur)
3951 {
3952 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3953 grub_printf("name:<%s>\n\n", cur->name);
3954 cur = cur->next;
3955 }
3956
3957 return 0;
3958 }
3959
3960 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3961 {
3962 (void)ctxt;
3963 (void)argc;
3964 (void)args;
3965
3966 ventoy_plugin_dump_injection();
3967
3968 return 0;
3969 }
3970
3971 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3972 {
3973 (void)ctxt;
3974 (void)argc;
3975 (void)args;
3976
3977 ventoy_plugin_dump_auto_install();
3978
3979 return 0;
3980 }
3981
3982 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3983 {
3984 (void)ctxt;
3985 (void)argc;
3986 (void)args;
3987
3988 ventoy_plugin_dump_persistence();
3989
3990 return 0;
3991 }
3992
3993 static int ventoy_check_mode_by_name(char *filename, const char *suffix)
3994 {
3995 int i;
3996 int len1;
3997 int len2;
3998
3999 len1 = (int)grub_strlen(filename);
4000 len2 = (int)grub_strlen(suffix);
4001
4002 if (len1 <= len2)
4003 {
4004 return 0;
4005 }
4006
4007 for (i = len1 - 1; i >= 0; i--)
4008 {
4009 if (filename[i] == '.')
4010 {
4011 break;
4012 }
4013 }
4014
4015 if (i < len2 + 1)
4016 {
4017 return 0;
4018 }
4019
4020 if (filename[i - len2 - 1] != '_')
4021 {
4022 return 0;
4023 }
4024
4025 if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0)
4026 {
4027 return 1;
4028 }
4029
4030 return 0;
4031 }
4032
4033 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4034 {
4035 (void)ctxt;
4036 (void)argc;
4037 (void)args;
4038
4039 if (argc != 1 && argc != 2)
4040 {
4041 return 1;
4042 }
4043
4044 if (args[0][0] == '0')
4045 {
4046 if (g_ventoy_memdisk_mode)
4047 {
4048 return 0;
4049 }
4050
4051 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk"))
4052 {
4053 return 0;
4054 }
4055
4056 return 1;
4057 }
4058 else if (args[0][0] == '1')
4059 {
4060 return g_ventoy_iso_raw ? 0 : 1;
4061 }
4062 else if (args[0][0] == '2')
4063 {
4064 return g_ventoy_iso_uefi_drv ? 0 : 1;
4065 }
4066 else if (args[0][0] == '3')
4067 {
4068 if (g_ventoy_grub2_mode)
4069 {
4070 return 0;
4071 }
4072
4073 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2"))
4074 {
4075 return 0;
4076 }
4077
4078 return 1;
4079 }
4080 else if (args[0][0] == '4')
4081 {
4082 if (g_ventoy_wimboot_mode)
4083 {
4084 return 0;
4085 }
4086
4087 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot"))
4088 {
4089 return 0;
4090 }
4091
4092 return 1;
4093 }
4094
4095 return 1;
4096 }
4097
4098 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
4099 {
4100 static int configfile_mode = 0;
4101 char memfile[128] = {0};
4102
4103 (void)ctxt;
4104 (void)argc;
4105 (void)args;
4106
4107 /*
4108 * args[0]: 0:normal 1:configfile
4109 * args[1]: 0:list_buf 1:tree_buf
4110 */
4111
4112 if (argc != 2)
4113 {
4114 debug("Invalid argc %d\n", argc);
4115 return 0;
4116 }
4117
4118 VTOY_CMD_CHECK(1);
4119
4120 if (args[0][0] == '0')
4121 {
4122 if (args[1][0] == '0')
4123 {
4124 grub_script_execute_sourcecode(g_list_script_buf);
4125 }
4126 else
4127 {
4128 grub_script_execute_sourcecode(g_tree_script_buf);
4129 }
4130 }
4131 else
4132 {
4133 if (configfile_mode)
4134 {
4135 debug("Now already in F3 mode %d\n", configfile_mode);
4136 return 0;
4137 }
4138
4139 if (args[1][0] == '0')
4140 {
4141 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4142 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
4143 }
4144 else
4145 {
4146 g_ventoy_last_entry = -1;
4147 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4148 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
4149 }
4150
4151 configfile_mode = 1;
4152 grub_script_execute_sourcecode(memfile);
4153 configfile_mode = 0;
4154 }
4155
4156 return 0;
4157 }
4158
4159 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
4160 {
4161 grub_file_t file;
4162
4163 (void)ctxt;
4164
4165 if (argc != 1)
4166 {
4167 return 1;
4168 }
4169
4170 g_ventoy_case_insensitive = 1;
4171 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4172 g_ventoy_case_insensitive = 0;
4173
4174 grub_errno = 0;
4175
4176 if (file)
4177 {
4178 grub_file_close(file);
4179 return 0;
4180 }
4181 return 1;
4182 }
4183
4184 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
4185 {
4186 int id = 0;
4187 int find = 0;
4188 grub_disk_t disk;
4189 const char *isopath = NULL;
4190 char hdname[32];
4191 ventoy_mbr_head mbr;
4192
4193 (void)ctxt;
4194 (void)argc;
4195
4196 if (argc != 1)
4197 {
4198 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
4199 }
4200
4201 isopath = grub_env_get("vtoy_iso_part");
4202 if (!isopath)
4203 {
4204 debug("isopath is null %p\n", isopath);
4205 return 0;
4206 }
4207
4208 debug("isopath is %s\n", isopath);
4209
4210 for (id = 0; id < 30 && (find == 0); id++)
4211 {
4212 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
4213 if (grub_strstr(isopath, hdname))
4214 {
4215 debug("skip %s ...\n", hdname);
4216 continue;
4217 }
4218
4219 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
4220
4221 disk = grub_disk_open(hdname);
4222 if (!disk)
4223 {
4224 debug("%s not exist\n", hdname);
4225 break;
4226 }
4227
4228 grub_memset(&mbr, 0, sizeof(mbr));
4229 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
4230 {
4231 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
4232 {
4233 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
4234 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
4235 {
4236
4237 grub_env_set(args[0], hdname);
4238 find = 1;
4239 }
4240 }
4241 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
4242 }
4243 else
4244 {
4245 debug("read %s failed\n", hdname);
4246 }
4247
4248 grub_disk_close(disk);
4249 }
4250
4251 return 0;
4252 }
4253
4254 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
4255 {
4256 int len = 1024;
4257 grub_file_t file;
4258 char *buf = NULL;
4259
4260 (void)ctxt;
4261 (void)argc;
4262
4263 if (argc != 2)
4264 {
4265 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
4266 }
4267
4268 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4269 if (!file)
4270 {
4271 debug("failed to open file %s\n", args[0]);
4272 return 0;
4273 }
4274
4275 buf = grub_malloc(len);
4276 if (!buf)
4277 {
4278 goto end;
4279 }
4280
4281 buf[len - 1] = 0;
4282 grub_file_read(file, buf, len - 1);
4283
4284 ventoy_get_line(buf);
4285 ventoy_set_env(args[1], buf);
4286
4287 end:
4288
4289 grub_check_free(buf);
4290 grub_file_close(file);
4291
4292 return 0;
4293 }
4294
4295 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
4296 {
4297 grub_uint64_t end_max = 0;
4298 int *pCnt = (int *)data;
4299
4300 (void)disk;
4301
4302 (*pCnt)++;
4303 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
4304 "0 %llu linear /dev/ventoy %llu\n",
4305 (ulonglong)partition->len, (ulonglong)partition->start);
4306
4307 end_max = (partition->len + partition->start) * 512;
4308 if (end_max > g_part_end_max)
4309 {
4310 g_part_end_max = end_max;
4311 }
4312
4313 return 0;
4314 }
4315
4316 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
4317 {
4318 int cnt = 0;
4319 char *device_name = NULL;
4320 grub_device_t dev = NULL;
4321 char buf[64];
4322
4323 (void)ctxt;
4324
4325 g_part_list_pos = 0;
4326 g_part_end_max = 0;
4327 grub_env_unset("vtoy_img_part_file");
4328
4329 if (argc != 1)
4330 {
4331 return 1;
4332 }
4333
4334 device_name = grub_file_get_device_name(args[0]);
4335 if (!device_name)
4336 {
4337 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
4338 goto end;
4339 }
4340
4341 dev = grub_device_open(device_name);
4342 if (!dev)
4343 {
4344 debug("grub_device_open failed, %s\n", device_name);
4345 goto end;
4346 }
4347
4348 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
4349
4350 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
4351 grub_env_set("vtoy_img_part_file", buf);
4352
4353 grub_snprintf(buf, sizeof(buf), "%d", cnt);
4354 grub_env_set("vtoy_img_part_cnt", buf);
4355
4356 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max);
4357 grub_env_set("vtoy_img_max_part_end", buf);
4358
4359 end:
4360
4361 check_free(device_name, grub_free);
4362 check_free(dev, grub_device_close);
4363
4364 return 0;
4365 }
4366
4367
4368 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
4369 {
4370 int rc = 1;
4371 grub_file_t file;
4372 char *buf = NULL;
4373
4374 (void)ctxt;
4375 (void)argc;
4376
4377 if (argc != 2)
4378 {
4379 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
4380 }
4381
4382 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4383 if (!file)
4384 {
4385 debug("failed to open file %s\n", args[0]);
4386 return 1;
4387 }
4388
4389 buf = grub_malloc(file->size + 1);
4390 if (!buf)
4391 {
4392 goto end;
4393 }
4394
4395 buf[file->size] = 0;
4396 grub_file_read(file, buf, file->size);
4397
4398 if (grub_strstr(buf, args[1]))
4399 {
4400 rc = 0;
4401 }
4402
4403 end:
4404
4405 grub_check_free(buf);
4406 grub_file_close(file);
4407
4408 return rc;
4409 }
4410
4411 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
4412 {
4413 int len;
4414 grub_file_t file;
4415 char buf[64];
4416 grub_uint64_t size;
4417 ventoy_iso9660_vd pvd;
4418
4419 (void)ctxt;
4420 (void)argc;
4421
4422 if (argc != 4)
4423 {
4424 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
4425 }
4426
4427 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4428 if (!file)
4429 {
4430 debug("failed to open file %s\n", args[0]);
4431 return 0;
4432 }
4433
4434 grub_file_seek(file, 16 * 2048);
4435 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
4436 if (len != sizeof(pvd))
4437 {
4438 debug("failed to read pvd %d\n", len);
4439 goto end;
4440 }
4441
4442 grub_memset(buf, 0, sizeof(buf));
4443 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
4444 ventoy_set_env(args[1], buf);
4445
4446 grub_memset(buf, 0, sizeof(buf));
4447 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
4448 ventoy_set_env(args[2], buf);
4449
4450 size = pvd.space;
4451 size *= 2048;
4452 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
4453 ventoy_set_env(args[3], buf);
4454
4455 end:
4456 grub_file_close(file);
4457
4458 return 0;
4459 }
4460
4461 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
4462 {
4463 int len;
4464 grub_file_t file;
4465 char buf[64];
4466
4467 (void)ctxt;
4468 (void)argc;
4469
4470 if (argc != 2)
4471 {
4472 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
4473 }
4474
4475 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4476 if (!file)
4477 {
4478 debug("failed to open file %s\n", args[0]);
4479 return 0;
4480 }
4481
4482 grub_memset(buf, 0, sizeof(buf));
4483 grub_file_seek(file, 16 * 2048 + 813);
4484 len = (int)grub_file_read(file, buf, 17);
4485 if (len != 17)
4486 {
4487 debug("failed to read create date %d\n", len);
4488 goto end;
4489 }
4490
4491 ventoy_set_env(args[1], buf);
4492
4493 end:
4494 grub_file_close(file);
4495
4496 return 0;
4497 }
4498
4499 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4500 {
4501 (void)ctxt;
4502 (void)argc;
4503 (void)args;
4504
4505 ventoy_env_hook_root(1);
4506
4507 return 0;
4508 }
4509
4510 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4511 {
4512 (void)ctxt;
4513 (void)argc;
4514 (void)args;
4515
4516 ventoy_env_hook_root(0);
4517
4518 return 0;
4519 }
4520
4521 #ifdef GRUB_MACHINE_EFI
4522 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4523 {
4524 int ret = 1;
4525 grub_uint8_t *var;
4526 grub_size_t size;
4527 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4528
4529 (void)ctxt;
4530 (void)argc;
4531 (void)args;
4532
4533 var = grub_efi_get_variable("SecureBoot", &global, &size);
4534 if (var && *var == 1)
4535 {
4536 return 0;
4537 }
4538
4539 return ret;
4540 }
4541 #else
4542 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4543 {
4544 (void)ctxt;
4545 (void)argc;
4546 (void)args;
4547 return 1;
4548 }
4549 #endif
4550
4551 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
4552 {
4553 int i;
4554 int ret = 1;
4555 grub_file_t file;
4556 grub_uint64_t FileSectors = 0;
4557 ventoy_gpt_info *gpt = NULL;
4558 ventoy_part_table *pt = NULL;
4559 grub_uint8_t zeroguid[16] = {0};
4560
4561 (void)ctxt;
4562 (void)argc;
4563
4564 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4565 if (!file)
4566 {
4567 debug("failed to open file %s\n", args[0]);
4568 return 1;
4569 }
4570
4571 if (file->size % 512)
4572 {
4573 debug("unaligned file size: %llu\n", (ulonglong)file->size);
4574 goto out;
4575 }
4576
4577 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
4578 if (!gpt)
4579 {
4580 goto out;
4581 }
4582
4583 FileSectors = file->size / 512;
4584
4585 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
4586 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
4587 {
4588 debug("This is EFI partition table\n");
4589
4590 for (i = 0; i < 128; i++)
4591 {
4592 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
4593 {
4594 if (FileSectors < gpt->PartTbl[i].LastLBA)
4595 {
4596 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4597 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
4598 goto out;
4599 }
4600 }
4601 }
4602 }
4603 else
4604 {
4605 debug("This is MBR partition table\n");
4606
4607 for (i = 0; i < 4; i++)
4608 {
4609 pt = gpt->MBR.PartTbl + i;
4610 if (FileSectors < pt->StartSectorId + pt->SectorCount)
4611 {
4612 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4613 (ulonglong)(pt->StartSectorId + pt->SectorCount),
4614 (ulonglong)FileSectors);
4615 goto out;
4616 }
4617 }
4618 }
4619
4620 ret = 0;
4621
4622 out:
4623 grub_file_close(file);
4624 grub_check_free(gpt);
4625 grub_errno = GRUB_ERR_NONE;
4626 return ret;
4627 }
4628
4629 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
4630 {
4631 int i;
4632 int ret;
4633
4634 (void)ctxt;
4635 (void)argc;
4636 (void)args;
4637
4638 for (i = 0; i < 500; i++)
4639 {
4640 ret = grub_getkey_noblock();
4641 if (ret == GRUB_TERM_NO_KEY)
4642 {
4643 break;
4644 }
4645 }
4646
4647 if (i >= 500)
4648 {
4649 grub_cls();
4650 grub_printf("\n\n Still have key input after clear.\n");
4651 grub_refresh();
4652 grub_sleep(5);
4653 }
4654
4655 return 0;
4656 }
4657
4658 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4659 {
4660 int i;
4661 int buflen;
4662 int datalen;
4663 int loclen;
4664 int img_chunk_num;
4665 int image_sector_size;
4666 char cmd[64];
4667 ventoy_chain_head *chain;
4668 ventoy_img_chunk *chunk;
4669 ventoy_os_param *osparam;
4670 ventoy_image_location *location;
4671 ventoy_image_disk_region *region;
4672 struct grub_acpi_table_header *acpi;
4673
4674 (void)ctxt;
4675
4676 if (argc != 2)
4677 {
4678 return 1;
4679 }
4680
4681 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4682
4683 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4684 if (!chain)
4685 {
4686 return 1;
4687 }
4688
4689 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4690
4691 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4692 {
4693 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4694 return 1;
4695 }
4696
4697 img_chunk_num = chain->img_chunk_num;
4698
4699 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4700 datalen = sizeof(ventoy_os_param) + loclen;
4701
4702 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4703 acpi = grub_zalloc(buflen);
4704 if (!acpi)
4705 {
4706 return 1;
4707 }
4708
4709 /* Step1: Fill acpi table header */
4710 grub_memcpy(acpi->signature, "VTOY", 4);
4711 acpi->length = buflen;
4712 acpi->revision = 1;
4713 grub_memcpy(acpi->oemid, "VENTOY", 6);
4714 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4715 acpi->oemrev = 1;
4716 acpi->creator_id[0] = 1;
4717 acpi->creator_rev = 1;
4718
4719 /* Step2: Fill data */
4720 osparam = (ventoy_os_param *)(acpi + 1);
4721 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4722 osparam->vtoy_img_location_addr = 0;
4723 osparam->vtoy_img_location_len = loclen;
4724 osparam->chksum = 0;
4725 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4726
4727 location = (ventoy_image_location *)(osparam + 1);
4728 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4729 location->image_sector_size = image_sector_size;
4730 location->disk_sector_size = chain->disk_sector_size;
4731 location->region_count = img_chunk_num;
4732
4733 region = location->regions;
4734 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4735 if (512 == image_sector_size)
4736 {
4737 for (i = 0; i < img_chunk_num; i++)
4738 {
4739 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4740 region->image_start_sector = chunk->img_start_sector * 4;
4741 region->disk_start_sector = chunk->disk_start_sector;
4742 region++;
4743 chunk++;
4744 }
4745 }
4746 else
4747 {
4748 for (i = 0; i < img_chunk_num; i++)
4749 {
4750 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4751 region->image_start_sector = chunk->img_start_sector;
4752 region->disk_start_sector = chunk->disk_start_sector;
4753 region++;
4754 chunk++;
4755 }
4756 }
4757
4758 /* Step3: Fill acpi checksum */
4759 acpi->checksum = 0;
4760 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4761
4762 /* load acpi table */
4763 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4764 grub_script_execute_sourcecode(cmd);
4765
4766 grub_free(acpi);
4767
4768 VENTOY_CMD_RETURN(0);
4769 }
4770
4771 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4772 {
4773 (void)ctxt;
4774 (void)argc;
4775 (void)args;
4776
4777 g_ventoy_last_entry_back = g_ventoy_last_entry;
4778 g_ventoy_last_entry = -1;
4779
4780 return 0;
4781 }
4782
4783 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4784 {
4785 (void)ctxt;
4786 (void)argc;
4787 (void)args;
4788
4789 g_ventoy_last_entry = g_ventoy_last_entry_back;
4790
4791 return 0;
4792 }
4793
4794 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4795 {
4796 const char *pos = filename + 1;
4797
4798 if (info->dir)
4799 {
4800 while (*pos)
4801 {
4802 if (*pos == '.')
4803 {
4804 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4805 {
4806 grub_strncpy((char *)data, filename, 128);
4807 return 1;
4808 }
4809 }
4810 pos++;
4811 }
4812 }
4813
4814 return 0;
4815 }
4816
4817 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4818 {
4819 int rc = 1;
4820 char *device_name = NULL;
4821 grub_device_t dev = NULL;
4822 grub_fs_t fs = NULL;
4823 char buf[128] = {0};
4824
4825 (void)ctxt;
4826
4827 if (argc != 3)
4828 {
4829 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4830 return 1;
4831 }
4832
4833 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4834
4835 device_name = grub_file_get_device_name(args[0]);
4836 if (!device_name)
4837 {
4838 debug("grub_file_get_device_name failed, %s\n", args[0]);
4839 goto end;
4840 }
4841
4842 dev = grub_device_open(device_name);
4843 if (!dev)
4844 {
4845 debug("grub_device_open failed, %s\n", device_name);
4846 goto end;
4847 }
4848
4849 fs = grub_fs_probe(dev);
4850 if (!fs)
4851 {
4852 debug("grub_fs_probe failed, %s\n", device_name);
4853 goto end;
4854 }
4855
4856 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4857
4858 if (buf[0])
4859 {
4860 ventoy_set_env(args[2], buf);
4861 }
4862
4863 rc = 0;
4864
4865 end:
4866
4867 check_free(device_name, grub_free);
4868 check_free(dev, grub_device_close);
4869
4870 return rc;
4871 }
4872
4873 int ventoy_load_part_table(const char *diskname)
4874 {
4875 char name[64];
4876 int ret;
4877 grub_disk_t disk;
4878 grub_device_t dev;
4879
4880 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4881 if (!g_ventoy_part_info)
4882 {
4883 return 1;
4884 }
4885
4886 disk = grub_disk_open(diskname);
4887 if (!disk)
4888 {
4889 debug("Failed to open disk %s\n", diskname);
4890 return 1;
4891 }
4892
4893 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4894
4895 g_ventoy_disk_bios_id = disk->id;
4896
4897 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4898 grub_disk_close(disk);
4899
4900 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4901 dev = grub_device_open(name);
4902 if (dev)
4903 {
4904 /* Check for official Ventoy device */
4905 ret = ventoy_check_official_device(dev);
4906 grub_device_close(dev);
4907
4908 if (ret)
4909 {
4910 return 1;
4911 }
4912 }
4913
4914 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4915 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4916
4917 return 0;
4918 }
4919
4920 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4921 {
4922 int ret;
4923
4924 (void)argc;
4925 (void)ctxt;
4926
4927 ret = ventoy_load_part_table(args[0]);
4928 if (ret)
4929 {
4930 grub_exit();
4931 }
4932
4933 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4934 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4935
4936 return 0;
4937 }
4938
4939 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4940 {
4941 int ret = 1;
4942 const char *vcfg = NULL;
4943
4944 (void)argc;
4945 (void)ctxt;
4946
4947 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4948 if (vcfg)
4949 {
4950 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4951 grub_env_set(args[1], vcfg);
4952 ret = 0;
4953 }
4954 else
4955 {
4956 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4957 }
4958
4959 grub_errno = 0;
4960 return ret;
4961 }
4962
4963
4964 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4965 {
4966 int id;
4967 grub_uint8_t zeroguid[16] = {0};
4968
4969 (void)argc;
4970 (void)ctxt;
4971
4972 id = (int)grub_strtoul(args[0], NULL, 10);
4973 grub_errno = 0;
4974
4975 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4976 {
4977 if (id >= 1 && id <= 128)
4978 {
4979 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4980 {
4981 return 0;
4982 }
4983 }
4984 }
4985 else
4986 {
4987 if (id >= 1 && id <= 4)
4988 {
4989 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4990 {
4991 return 0;
4992 }
4993 }
4994 }
4995
4996 return 1;
4997 }
4998
4999 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
5000 {
5001 int rc = 1;
5002 char *device_name = NULL;
5003 grub_device_t dev = NULL;
5004 grub_fs_t fs = NULL;
5005 char *label = NULL;
5006
5007 (void)ctxt;
5008
5009 debug("get fs label for %s\n", args[0]);
5010
5011 if (argc != 2)
5012 {
5013 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
5014 return 1;
5015 }
5016
5017 device_name = grub_file_get_device_name(args[0]);
5018 if (!device_name)
5019 {
5020 debug("grub_file_get_device_name failed, %s\n", args[0]);
5021 goto end;
5022 }
5023
5024 dev = grub_device_open(device_name);
5025 if (!dev)
5026 {
5027 debug("grub_device_open failed, %s\n", device_name);
5028 goto end;
5029 }
5030
5031 fs = grub_fs_probe(dev);
5032 if (NULL == fs || NULL == fs->fs_label)
5033 {
5034 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
5035 goto end;
5036 }
5037
5038 fs->fs_label(dev, &label);
5039 if (label)
5040 {
5041 debug("label=<%s>\n", label);
5042 ventoy_set_env(args[1], label);
5043 grub_free(label);
5044 }
5045
5046 rc = 0;
5047
5048 end:
5049
5050 check_free(device_name, grub_free);
5051 check_free(dev, grub_device_close);
5052
5053 return rc;
5054 }
5055
5056 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5057 {
5058 if (!info->dir)
5059 {
5060 grub_snprintf((char *)data, 256, "%s", filename);
5061 return 1;
5062 }
5063
5064 return 0;
5065 }
5066
5067 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5068 {
5069 if (info->dir && filename && filename[0] != '.')
5070 {
5071 grub_snprintf((char *)data, 256, "%s", filename);
5072 return 1;
5073 }
5074
5075 return 0;
5076 }
5077
5078 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
5079 {
5080 int rc = 1;
5081 char *device_name = NULL;
5082 grub_device_t dev = NULL;
5083 grub_fs_t fs = NULL;
5084 char name[256] ={0};
5085
5086 if (argc != 3)
5087 {
5088 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
5089 return 1;
5090 }
5091
5092 device_name = grub_file_get_device_name(args[0]);
5093 if (!device_name)
5094 {
5095 debug("grub_file_get_device_name failed, %s\n", args[0]);
5096 goto end;
5097 }
5098
5099 dev = grub_device_open(device_name);
5100 if (!dev)
5101 {
5102 debug("grub_device_open failed, %s\n", device_name);
5103 goto end;
5104 }
5105
5106 fs = grub_fs_probe(dev);
5107 if (!fs)
5108 {
5109 debug("grub_fs_probe failed, %s\n", device_name);
5110 goto end;
5111 }
5112
5113 fs->fs_dir(dev, args[1], hook, name);
5114 if (name[0])
5115 {
5116 ventoy_set_env(args[2], name);
5117 }
5118
5119 rc = 0;
5120
5121 end:
5122
5123 check_free(device_name, grub_free);
5124 check_free(dev, grub_device_close);
5125
5126 return rc;
5127 }
5128
5129 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
5130 {
5131 (void)ctxt;
5132 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
5133 }
5134
5135 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
5136 {
5137 (void)ctxt;
5138 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
5139 }
5140
5141 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
5142 {
5143 char c;
5144 char *pos = NULL;
5145 char *end = NULL;
5146
5147 (void)ctxt;
5148
5149 if (argc != 2)
5150 {
5151 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
5152 return 1;
5153 }
5154
5155 for (pos = args[0]; *pos; pos++)
5156 {
5157 if (*pos == '.')
5158 {
5159 end = pos;
5160 }
5161 }
5162
5163 if (end)
5164 {
5165 c = *end;
5166 *end = 0;
5167 }
5168
5169 grub_env_set(args[1], args[0]);
5170
5171 if (end)
5172 {
5173 *end = c;
5174 }
5175
5176 return 0;
5177 }
5178
5179 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
5180 {
5181 int i;
5182 int len;
5183 const char *buf;
5184
5185 (void)ctxt;
5186
5187 if (argc != 2)
5188 {
5189 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
5190 return 1;
5191 }
5192
5193 buf = args[0];
5194 len = (int)grub_strlen(buf);
5195 for (i = len; i > 0; i--)
5196 {
5197 if (buf[i - 1] == '/')
5198 {
5199 grub_env_set(args[1], buf + i);
5200 return 0;
5201 }
5202 }
5203
5204 grub_env_set(args[1], buf);
5205
5206 return 0;
5207 }
5208
5209 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5210 {
5211 struct grub_video_mode_info info;
5212 char buf[32];
5213
5214 (void)ctxt;
5215 (void)argc;
5216 (void)args;
5217
5218 if (!g_video_mode_list)
5219 {
5220 ventoy_enum_video_mode();
5221 }
5222
5223 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5224 {
5225 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
5226 }
5227 else
5228 {
5229 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
5230 }
5231
5232 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
5233
5234 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
5235 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
5236
5237 VENTOY_CMD_RETURN(0);
5238 }
5239
5240 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5241 {
5242 struct grub_video_mode_info info;
5243 char buf[32];
5244
5245 (void)ctxt;
5246 (void)argc;
5247 (void)args;
5248
5249 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5250 {
5251 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
5252 }
5253 else
5254 {
5255 grub_snprintf(buf, sizeof(buf), "0x0x0");
5256 }
5257
5258 grub_env_set(args[0], buf);
5259
5260 VENTOY_CMD_RETURN(0);
5261 }
5262
5263 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5264 {
5265 int id;
5266 char buf[32];
5267
5268 (void)ctxt;
5269 (void)argc;
5270
5271 if (!g_video_mode_list)
5272 {
5273 return 0;
5274 }
5275
5276 id = (int)grub_strtoul(args[0], NULL, 10);
5277 if (id < g_video_mode_num)
5278 {
5279 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5280 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5281 }
5282
5283 grub_env_set(args[1], buf);
5284
5285 VENTOY_CMD_RETURN(0);
5286 }
5287
5288 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5289 {
5290 grub_uint32_t i;
5291 grub_uint32_t loadsector = 0;
5292 grub_file_t file;
5293 char value[32];
5294 grub_uint32_t boot_catlog = 0;
5295 grub_uint8_t buf[512];
5296
5297 (void)ctxt;
5298
5299 if (argc != 2)
5300 {
5301 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5302 return 1;
5303 }
5304
5305 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5306 if (!file)
5307 {
5308 debug("failed to open %s\n", args[0]);
5309 return 1;
5310 }
5311
5312 boot_catlog = ventoy_get_iso_boot_catlog(file);
5313 if (boot_catlog == 0)
5314 {
5315 debug("No bootcatlog found\n");
5316 grub_file_close(file);
5317 return 1;
5318 }
5319
5320 grub_memset(buf, 0, sizeof(buf));
5321 grub_file_seek(file, boot_catlog * 2048);
5322 grub_file_read(file, buf, sizeof(buf));
5323 grub_file_close(file);
5324
5325 for (i = 0; i < sizeof(buf); i += 32)
5326 {
5327 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5328 {
5329 if (buf[i + 32] == 0x88)
5330 {
5331 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5332 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5333 break;
5334 }
5335 }
5336 }
5337
5338 if (loadsector == 0)
5339 {
5340 debug("No EFI eltorito info found\n");
5341 return 1;
5342 }
5343
5344 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5345 grub_env_set(args[1], value);
5346 VENTOY_CMD_RETURN(0);
5347 }
5348
5349 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5350 {
5351 int curpos;
5352 int printlen;
5353 grub_size_t len;
5354 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5355
5356 if (pfsdir->initrd[0])
5357 {
5358 return 1;
5359 }
5360
5361 curpos = pfsdir->curpos;
5362 len = grub_strlen(filename);
5363
5364 if (info->dir)
5365 {
5366 if ((len == 1 && filename[0] == '.') ||
5367 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5368 {
5369 return 0;
5370 }
5371
5372 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5373 pfsdir->dircnt++;
5374
5375 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5376 pfsdir->curpos = curpos + printlen;
5377 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5378 pfsdir->curpos = curpos;
5379 pfsdir->fullpath[curpos] = 0;
5380 }
5381 else
5382 {
5383 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5384 pfsdir->filecnt++;
5385
5386 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5387 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5388 {
5389 if (info->size > 32 * VTOY_SIZE_1MB)
5390 {
5391 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5392 return 1;
5393 }
5394 }
5395 }
5396
5397 return 0;
5398 }
5399
5400 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5401 {
5402 int i;
5403 char *pos = NULL;
5404 char *device_name = NULL;
5405 grub_device_t dev = NULL;
5406 grub_fs_t fs = NULL;
5407 replace_fs_dir *pfsdir = NULL;
5408
5409 (void)ctxt;
5410
5411 if (argc != 2)
5412 {
5413 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5414 return 1;
5415 }
5416
5417 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5418 if (!pfsdir)
5419 {
5420 return 1;
5421 }
5422
5423 device_name = grub_file_get_device_name(args[0]);
5424 if (!device_name)
5425 {
5426 goto fail;
5427 }
5428
5429 dev = grub_device_open(device_name);
5430 if (!dev)
5431 {
5432 goto fail;
5433 }
5434
5435 fs = grub_fs_probe(dev);
5436 if (!fs)
5437 {
5438 goto fail;
5439 }
5440
5441 pfsdir->dev = dev;
5442 pfsdir->fs = fs;
5443 pfsdir->curpos = 1;
5444 pfsdir->fullpath[0] = '/';
5445 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5446
5447 if (pfsdir->initrd[0])
5448 {
5449 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5450
5451 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5452 {
5453 if (pfsdir->initrd[i] == '/')
5454 {
5455 pfsdir->initrd[i] = '\\';
5456 }
5457 }
5458
5459 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5460 grub_env_set(args[1], pos);
5461 }
5462 else
5463 {
5464 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5465 }
5466
5467 fail:
5468
5469 grub_check_free(pfsdir);
5470 grub_check_free(device_name);
5471 check_free(dev, grub_device_close);
5472
5473 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5474 }
5475
5476 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5477 {
5478 const char *pager = NULL;
5479
5480 (void)ctxt;
5481 (void)argc;
5482 (void)args;
5483
5484 pager = grub_env_get("pager");
5485 if (NULL == pager)
5486 {
5487 g_pager_flag = 1;
5488 grub_env_set("pager", "1");
5489 }
5490 else if (pager[0] == '1')
5491 {
5492 g_pager_flag = 0;
5493 }
5494 else
5495 {
5496 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5497 g_pager_flag = 2;
5498 grub_env_set("pager", "1");
5499 }
5500
5501 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5502 }
5503
5504 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5505 {
5506 (void)ctxt;
5507 (void)argc;
5508 (void)args;
5509
5510 if (g_pager_flag == 1)
5511 {
5512 grub_env_unset("pager");
5513 }
5514 else if (g_pager_flag == 2)
5515 {
5516 grub_env_set("pager", g_old_pager);
5517 }
5518
5519 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5520 }
5521
5522 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5523 {
5524 if (g_json_case_mis_path[0])
5525 {
5526 return 1;
5527 }
5528
5529 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5530 {
5531 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5532 return 1;
5533 }
5534 return 0;
5535 }
5536
5537 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5538 {
5539 char path[16];
5540 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5541
5542 if (g_json_case_mis_path[0])
5543 {
5544 return 1;
5545 }
5546
5547 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5548 {
5549 if (grub_strcasecmp(filename, "ventoy") == 0)
5550 {
5551 grub_snprintf(path, sizeof(path), "/%s", filename);
5552 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5553 if (g_json_case_mis_path[0])
5554 {
5555 return 1;
5556 }
5557 }
5558 }
5559
5560 return 0;
5561 }
5562
5563 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5564 {
5565 int fstype = 0;
5566 char *device_name = NULL;
5567 grub_device_t dev = NULL;
5568 grub_fs_t fs = NULL;
5569 chk_case_fs_dir fs_dir;
5570
5571 (void)ctxt;
5572 (void)argc;
5573 (void)args;
5574
5575 device_name = grub_file_get_device_name(args[0]);
5576 if (!device_name)
5577 {
5578 goto out;
5579 }
5580
5581 dev = grub_device_open(device_name);
5582 if (!dev)
5583 {
5584 goto out;
5585 }
5586
5587 fs = grub_fs_probe(dev);
5588 if (!fs)
5589 {
5590 goto out;
5591 }
5592
5593 fstype = ventoy_get_fs_type(fs->name);
5594 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5595 {
5596 goto out;
5597 }
5598
5599 g_json_case_mis_path[0] = 0;
5600 fs_dir.dev = dev;
5601 fs_dir.fs = fs;
5602 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5603
5604 if (g_json_case_mis_path[0])
5605 {
5606 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5607 }
5608
5609 out:
5610
5611 grub_check_free(device_name);
5612 check_free(dev, grub_device_close);
5613
5614 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5615 }
5616
5617 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5618 {
5619 grub_disk_t disk;
5620 grub_partition_t part;
5621 char priority_str[3]; /* Maximum value 15 */
5622
5623 (void)ctxt;
5624
5625 if (argc < 2 || argc > 3)
5626 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5627 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5628
5629 /* Open the disk if it exists */
5630 disk = grub_disk_open (args[0]);
5631 if (!disk)
5632 {
5633 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5634 "Not a disk");
5635 }
5636
5637 part = grub_partition_probe (disk, args[1]);
5638 if (!part)
5639 {
5640 grub_disk_close (disk);
5641 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5642 "No such partition");
5643 }
5644
5645 if (grub_strcmp (part->partmap->name, "gpt"))
5646 {
5647 grub_disk_close (disk);
5648 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5649 "Not a GPT partition");
5650 }
5651
5652 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5653 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5654
5655 if (argc == 3)
5656 {
5657 grub_env_set (args[2], priority_str);
5658 grub_env_export (args[2]);
5659 }
5660 else
5661 {
5662 grub_printf ("Priority is %s\n", priority_str);
5663 }
5664
5665 grub_disk_close (disk);
5666 return GRUB_ERR_NONE;
5667 }
5668
5669
5670 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5671 {
5672 int ret = 1;
5673 int joliet = 0;
5674 grub_file_t file = NULL;
5675 grub_uint32_t loadrba = 0;
5676 grub_uint32_t boot_catlog = 0;
5677 grub_uint8_t sector[512];
5678 boot_info_table *info = NULL;
5679
5680 (void)ctxt;
5681 (void)argc;
5682
5683 /* This also trigger a iso9660 fs parse */
5684 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5685 {
5686 return 0;
5687 }
5688
5689 joliet = grub_iso9660_is_joliet();
5690 if (joliet == 0)
5691 {
5692 return 1;
5693 }
5694
5695 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5696 if (!file)
5697 {
5698 debug("failed to open %s\n", args[0]);
5699 return 1;
5700 }
5701
5702 boot_catlog = ventoy_get_iso_boot_catlog(file);
5703 if (boot_catlog == 0)
5704 {
5705 debug("no bootcatlog found %u\n", boot_catlog);
5706 goto out;
5707 }
5708
5709 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5710 if (loadrba == 0)
5711 {
5712 debug("no bios eltorito rba found %u\n", loadrba);
5713 goto out;
5714 }
5715
5716 grub_file_seek(file, loadrba * 2048);
5717 grub_file_read(file, sector, 512);
5718
5719 info = (boot_info_table *)sector;
5720 if (info->bi_data0 == 0x7c6ceafa &&
5721 info->bi_data1 == 0x90900000 &&
5722 info->bi_PrimaryVolumeDescriptor == 16 &&
5723 info->bi_BootFileLocation == loadrba)
5724 {
5725 debug("bootloader is syslinux, %u.\n", loadrba);
5726 ret = 0;
5727 }
5728
5729 out:
5730
5731 grub_file_close(file);
5732 grub_errno = GRUB_ERR_NONE;
5733 return ret;
5734 }
5735
5736 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5737 {
5738 int n = 0;
5739 ventoy_vlnk_part *node;
5740
5741 (void)ctxt;
5742 (void)argc;
5743 (void)args;
5744
5745 for (node = g_vlnk_part_list; node; node = node->next)
5746 {
5747 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5748 ++n, node->device, node->disksig,
5749 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5750 }
5751
5752 return 0;
5753 }
5754
5755 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5756 {
5757 int len = 0;
5758
5759 (void)ctxt;
5760
5761 if (argc == 1)
5762 {
5763 len = (int)grub_strlen(args[0]);
5764 if (grub_file_is_vlnk_suffix(args[0], len))
5765 {
5766 return 0;
5767 }
5768 }
5769
5770 return 1;
5771 }
5772
5773 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5774 {
5775 int vlnk = 0;
5776 const char *name = NULL;
5777
5778 (void)ctxt;
5779
5780 if (argc == 2)
5781 {
5782 grub_env_unset(args[1]);
5783 name = grub_file_get_vlnk(args[0], &vlnk);
5784 if (vlnk)
5785 {
5786 debug("VLNK SRC: <%s>\n", args[0]);
5787 debug("VLNK DST: <%s>\n", name);
5788 grub_env_set(args[1], name);
5789 return 0;
5790 }
5791 }
5792
5793 return 1;
5794 }
5795
5796 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5797 {
5798 int ret = 1;
5799 int len = 0;
5800 grub_file_t file = NULL;
5801 ventoy_vlnk vlnk;
5802 char dst[512];
5803
5804 (void)ctxt;
5805
5806 if (argc != 1)
5807 {
5808 goto out;
5809 }
5810
5811 len = (int)grub_strlen(args[0]);
5812 if (!grub_file_is_vlnk_suffix(args[0], len))
5813 {
5814 grub_printf("Invalid vlnk suffix\n");
5815 goto out;
5816 }
5817
5818 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5819 if (!file)
5820 {
5821 grub_printf("Failed to open %s\n", args[0]);
5822 goto out;
5823 }
5824
5825 if (file->size != 32768)
5826 {
5827 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5828 goto out;
5829 }
5830
5831 grub_memset(&vlnk, 0, sizeof(vlnk));
5832 grub_file_read(file, &vlnk, sizeof(vlnk));
5833
5834 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5835
5836 out:
5837
5838 grub_refresh();
5839 check_free(file, grub_file_close);
5840 grub_errno = GRUB_ERR_NONE;
5841 return ret;
5842 }
5843
5844 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5845 {
5846 (void)ctxt;
5847 (void)argc;
5848 (void)args;
5849
5850 g_iso_vd_id_publisher[0] = 0;
5851 g_iso_vd_id_prepare[0] = 0;
5852 g_iso_vd_id_application[0] = 0;
5853
5854 return 0;
5855 }
5856
5857 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
5858 {
5859 int ret = 1;
5860 int offset = 318;
5861 grub_file_t file = NULL;
5862
5863 (void)ctxt;
5864 (void)argc;
5865
5866 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5867 if (!file)
5868 {
5869 grub_printf("Failed to open %s\n", args[0]);
5870 goto out;
5871 }
5872
5873 grub_file_seek(file, 16 * 2048 + offset);
5874 grub_file_read(file, g_iso_vd_id_publisher, 128);
5875
5876 offset += 128;
5877 grub_file_seek(file, 16 * 2048 + offset);
5878 grub_file_read(file, g_iso_vd_id_prepare, 128);
5879
5880 offset += 128;
5881 grub_file_seek(file, 16 * 2048 + offset);
5882 grub_file_read(file, g_iso_vd_id_application, 128);
5883
5884 out:
5885
5886 check_free(file, grub_file_close);
5887 grub_errno = GRUB_ERR_NONE;
5888 return ret;
5889 }
5890
5891 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
5892 {
5893 int ret = 1;
5894 char *id = g_iso_vd_id_publisher;
5895
5896 (void)ctxt;
5897 (void)argc;
5898
5899 if (args[0][0] == '1')
5900 {
5901 id = g_iso_vd_id_prepare;
5902 }
5903 else if (args[0][0] == '2')
5904 {
5905 id = g_iso_vd_id_application;
5906 }
5907
5908 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
5909 {
5910 ret = 0;
5911 }
5912
5913 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
5914 {
5915 ret = 0;
5916 }
5917
5918 grub_errno = GRUB_ERR_NONE;
5919 return ret;
5920 }
5921
5922 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
5923 {
5924 (void)ctxt;
5925 (void)argc;
5926
5927 g_ventoy_fn_mutex = 0;
5928 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
5929 {
5930 g_ventoy_fn_mutex = 1;
5931 }
5932
5933 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5934 }
5935
5936 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
5937 {
5938 grub_uint64_t total;
5939 grub_uint64_t org_required;
5940 grub_uint64_t new_required;
5941
5942 (void)ctxt;
5943 (void)argc;
5944 (void)args;
5945
5946 #ifdef GRUB_MACHINE_EFI
5947 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
5948 grub_printf("Total pages: %llu\n", (unsigned long long)total);
5949 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
5950 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
5951 #else
5952 (void)total;
5953 (void)org_required;
5954 (void)new_required;
5955 grub_printf("Non EFI mode!\n");
5956 #endif
5957
5958 grub_refresh();
5959
5960 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5961 }
5962
5963 static grub_err_t ventoy_cmd_need_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
5964 {
5965 const char *env = NULL;
5966
5967 (void)ctxt;
5968 (void)argc;
5969
5970 if (g_ventoy_memdisk_mode || g_ventoy_grub2_mode || g_ventoy_wimboot_mode || g_ventoy_iso_raw)
5971 {
5972 return 1;
5973 }
5974
5975 if (ventoy_check_mode_by_name(args[0], "vtmemdisk") ||
5976 ventoy_check_mode_by_name(args[0], "vtgrub2") ||
5977 ventoy_check_mode_by_name(args[0], "vtwimboot"))
5978 {
5979 return 1;
5980 }
5981
5982 env = grub_env_get("VTOY_SECONDARY_BOOT_MENU");
5983 if (env && env[0] == '0' && env[1] == 0)
5984 {
5985 return 1;
5986 }
5987
5988 return 0;
5989 }
5990
5991 static grub_err_t ventoy_cmd_show_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
5992 {
5993 int n = 0;
5994 int pos = 0;
5995 int len = 0;
5996 int select = 0;
5997 int timeout = 0;
5998 char *cmd = NULL;
5999 const char *env = NULL;
6000 ulonglong fsize = 0;
6001 char cfgfile[128];
6002 int seldata[16] = {0};
6003
6004 (void)ctxt;
6005 (void)argc;
6006
6007 len = 8 * VTOY_SIZE_1KB;
6008 cmd = (char *)grub_malloc(len);
6009 if (!cmd)
6010 {
6011 return 1;
6012 }
6013
6014 g_vtoy_secondary_need_recover = 0;
6015 grub_env_unset("VTOY_CHKSUM_FILE_PATH");
6016
6017 env = grub_env_get("VTOY_SECONDARY_TIMEOUT");
6018 if (env)
6019 {
6020 timeout = (int)grub_strtol(env, NULL, 10);
6021 }
6022
6023 if (timeout > 0)
6024 {
6025 vtoy_len_ssprintf(cmd, pos, len, "set timeout=%d\n", timeout);
6026 }
6027
6028 fsize = grub_strtoull(args[2], NULL, 10);
6029
6030 vtoy_dummy_menuentry(cmd, pos, len, "Boot in normal mode", "second_normal"); seldata[n++] = 1;
6031
6032 if (grub_strcmp(args[1], "Unix") != 0)
6033 {
6034 if (grub_strcmp(args[1], "Windows") == 0)
6035 {
6036 vtoy_dummy_menuentry(cmd, pos, len, "Boot in wimboot mode", "second_wimboot"); seldata[n++] = 2;
6037 }
6038 else
6039 {
6040 vtoy_dummy_menuentry(cmd, pos, len, "Boot in grub2 mode", "second_grub2"); seldata[n++] = 3;
6041 }
6042
6043 if (fsize <= VTOY_SIZE_1GB)
6044 {
6045 vtoy_dummy_menuentry(cmd, pos, len, "Boot in memdisk mode", "second_memdisk"); seldata[n++] = 4;
6046 }
6047 }
6048
6049 vtoy_dummy_menuentry(cmd, pos, len, "File checksum", "second_checksum"); seldata[n++] = 5;
6050
6051 do {
6052 g_ventoy_menu_esc = 1;
6053 g_ventoy_suppress_esc = 1;
6054 g_ventoy_suppress_esc_default = 0;
6055 g_ventoy_secondary_menu_on = 1;
6056 grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos);
6057 grub_script_execute_sourcecode(cfgfile);
6058 g_ventoy_menu_esc = 0;
6059 g_ventoy_suppress_esc = 0;
6060 g_ventoy_suppress_esc_default = 1;
6061 g_ventoy_secondary_menu_on = 0;
6062
6063 select = seldata[g_ventoy_last_entry];
6064
6065 if (select == 2)
6066 {
6067 g_ventoy_wimboot_mode = 1;
6068 g_vtoy_secondary_need_recover = 1;
6069 }
6070 else if (select == 3)
6071 {
6072 g_ventoy_grub2_mode = 1;
6073 g_vtoy_secondary_need_recover = 2;
6074 }
6075 else if (select == 4)
6076 {
6077 g_ventoy_memdisk_mode = 1;
6078 g_vtoy_secondary_need_recover = 3;
6079 }
6080 else if (select == 5)
6081 {
6082 grub_env_set("VTOY_CHKSUM_FILE_PATH", args[0]);
6083 grub_script_execute_sourcecode("configfile $vtoy_efi_part/grub/checksum.cfg");
6084 }
6085 }while (select == 5);
6086
6087 grub_free(cmd);
6088 return 0;
6089 }
6090
6091 static grub_err_t ventoy_cmd_secondary_recover_mode(grub_extcmd_context_t ctxt, int argc, char **args)
6092 {
6093 (void)ctxt;
6094 (void)argc;
6095 (void)args;
6096
6097 if (g_vtoy_secondary_need_recover == 1)
6098 {
6099 g_ventoy_wimboot_mode = 0;
6100 }
6101 else if (g_vtoy_secondary_need_recover == 2)
6102 {
6103 g_ventoy_grub2_mode = 0;
6104 }
6105 else if (g_vtoy_secondary_need_recover == 3)
6106 {
6107 g_ventoy_memdisk_mode = 0;
6108 }
6109
6110 g_vtoy_secondary_need_recover = 0;
6111
6112 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6113 }
6114
6115 static grub_err_t ventoy_cmd_fs_ignore_case(grub_extcmd_context_t ctxt, int argc, char **args)
6116 {
6117 (void)ctxt;
6118 (void)argc;
6119
6120 if (args[0][0] == '0')
6121 {
6122 g_ventoy_case_insensitive = 0;
6123 }
6124 else
6125 {
6126 g_ventoy_case_insensitive = 1;
6127 }
6128
6129 return 0;
6130 }
6131
6132 int ventoy_env_init(void)
6133 {
6134 int i;
6135 char buf[64];
6136
6137 grub_env_set("vtdebug_flag", "");
6138
6139 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
6140 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6141 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6142 for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++)
6143 {
6144 g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size);
6145 }
6146
6147 ventoy_filt_register(0, ventoy_wrapper_open);
6148
6149 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
6150 if (g_grub_param)
6151 {
6152 g_grub_param->grub_env_get = grub_env_get;
6153 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
6154 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
6155 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
6156 grub_env_set("env_param", buf);
6157 grub_env_set("ventoy_env_param", buf);
6158
6159 grub_env_export("env_param");
6160 grub_env_export("ventoy_env_param");
6161 }
6162
6163 grub_env_export("vtoy_winpeshl_ini_addr");
6164 grub_env_export("vtoy_winpeshl_ini_size");
6165
6166 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
6167 grub_env_set("vtoy_chain_file_size", buf);
6168 grub_env_export("vtoy_chain_file_size");
6169
6170 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
6171 grub_env_set("vtoy_chain_file_read", buf);
6172 grub_env_export("vtoy_chain_file_read");
6173
6174 return 0;
6175 }
6176
6177
6178
6179 static cmd_para ventoy_cmds[] =
6180 {
6181 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
6182 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
6183 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
6184 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
6185 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
6186 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
6187 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
6188 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6189 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6190 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
6191 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
6192 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
6193 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
6194 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
6195 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
6196 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
6197 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
6198 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
6199 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
6200 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
6201 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
6202 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
6203 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
6204 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
6205 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
6206 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
6207 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
6208
6209 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
6210 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
6211 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
6212 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
6213 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
6214 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
6215 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
6216
6217 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
6218 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
6219 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
6220 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
6221 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
6222 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
6223 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
6224 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
6225 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
6226 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
6227
6228
6229 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
6230 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
6231 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
6232 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
6233 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
6234 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
6235 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
6236 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
6237 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
6238 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
6239 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
6240
6241 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
6242 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
6243 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
6244 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
6245 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
6246 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
6247 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
6248
6249 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6250 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6251 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
6252 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
6253 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
6254 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
6255 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
6256 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
6257 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
6258 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
6259
6260 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
6261 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
6262 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
6263 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
6264 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
6265 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
6266 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
6267 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
6268 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
6269
6270 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
6271 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
6272 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
6273 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
6274
6275
6276 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
6277 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
6278 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
6279
6280 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
6281 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
6282 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
6283
6284
6285 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
6286 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
6287 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
6288 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
6289 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
6290 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
6291 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
6292 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
6293 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
6294 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
6295 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
6296 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
6297 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
6298 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
6299
6300 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
6301 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
6302 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
6303 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
6304 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
6305 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
6306 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
6307 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
6308 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
6309 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
6310 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
6311 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
6312
6313 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
6314 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
6315 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
6316 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
6317 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
6318 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
6319 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
6320 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
6321 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
6322 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
6323 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
6324 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
6325 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
6326 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
6327 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
6328 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
6329 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
6330 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
6331 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
6332 { "vt_is_standard_winiso", ventoy_cmd_is_standard_winiso, 0, NULL, "", "", NULL },
6333 { "vt_sel_winpe_wim", ventoy_cmd_sel_winpe_wim, 0, NULL, "", "", NULL },
6334 { "vt_need_secondary_menu", ventoy_cmd_need_secondary_menu, 0, NULL, "", "", NULL },
6335 { "vt_show_secondary_menu", ventoy_cmd_show_secondary_menu, 0, NULL, "", "", NULL },
6336 { "vt_fs_ignore_case", ventoy_cmd_fs_ignore_case, 0, NULL, "", "", NULL },
6337 { "vt_systemd_menu", ventoy_cmd_linux_systemd_menu, 0, NULL, "", "", NULL },
6338 { "vt_secondary_recover_mode", ventoy_cmd_secondary_recover_mode, 0, NULL, "", "", NULL },
6339 };
6340
6341 int ventoy_register_all_cmd(void)
6342 {
6343 grub_uint32_t i;
6344 cmd_para *cur = NULL;
6345
6346 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6347 {
6348 cur = ventoy_cmds + i;
6349 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
6350 cur->summary, cur->description, cur->parser);
6351 }
6352
6353 return 0;
6354 }
6355
6356 int ventoy_unregister_all_cmd(void)
6357 {
6358 grub_uint32_t i;
6359
6360 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6361 {
6362 grub_unregister_extcmd(ventoy_cmds[i].cmd);
6363 }
6364
6365 return 0;
6366 }
6367
6368