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