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