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