]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
Support openwrt IMG file
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy.c
1 /******************************************************************************
2 * ventoy.c
3 *
4 * Copyright (c) 2020, 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/ventoy.h>
49 #include "ventoy_def.h"
50 #include "miniz.h"
51
52 GRUB_MOD_LICENSE ("GPLv3+");
53
54 int g_ventoy_debug = 0;
55 static int g_efi_os = 0xFF;
56 initrd_info *g_initrd_img_list = NULL;
57 initrd_info *g_initrd_img_tail = NULL;
58 int g_initrd_img_count = 0;
59 int g_valid_initrd_count = 0;
60 int g_default_menu_mode = 0;
61 int g_filt_dot_underscore_file = 0;
62 int g_sort_case_sensitive = 0;
63 int g_tree_view_menu_style = 0;
64 static grub_file_t g_old_file;
65 static int g_ventoy_last_entry_back;
66 static grub_uint32_t g_ventoy_plat_data;
67
68 char g_iso_path[256];
69 char g_img_swap_tmp_buf[1024];
70 img_info g_img_swap_tmp;
71 img_info *g_ventoy_img_list = NULL;
72
73 int g_ventoy_img_count = 0;
74
75 grub_device_t g_enum_dev = NULL;
76 grub_fs_t g_enum_fs = NULL;
77 int g_img_max_search_level = -1;
78 img_iterator_node g_img_iterator_head;
79 img_iterator_node *g_img_iterator_tail = NULL;
80
81 grub_uint8_t g_ventoy_break_level = 0;
82 grub_uint8_t g_ventoy_debug_level = 0;
83 grub_uint8_t g_ventoy_chain_type = 0;
84
85 grub_uint8_t *g_ventoy_cpio_buf = NULL;
86 grub_uint32_t g_ventoy_cpio_size = 0;
87 cpio_newc_header *g_ventoy_initrd_head = NULL;
88 grub_uint8_t *g_ventoy_runtime_buf = NULL;
89
90 int g_plugin_image_list = 0;
91
92 ventoy_grub_param *g_grub_param = NULL;
93
94 ventoy_guid g_ventoy_guid = VENTOY_GUID;
95
96 ventoy_img_chunk_list g_img_chunk_list;
97
98 int g_wimboot_enable = 0;
99 ventoy_img_chunk_list g_wimiso_chunk_list;
100 char *g_wimiso_path = NULL;
101
102 int g_vhdboot_enable = 0;
103
104 grub_uint64_t g_conf_replace_offset = 0;
105 grub_uint64_t g_svd_replace_offset = 0;
106 conf_replace *g_conf_replace_node = NULL;
107 grub_uint8_t *g_conf_replace_new_buf = NULL;
108 int g_conf_replace_new_len = 0;
109 int g_conf_replace_new_len_align = 0;
110
111 ventoy_gpt_info *g_ventoy_part_info = NULL;
112 grub_uint64_t g_ventoy_disk_size = 0;
113
114 static char *g_tree_script_buf = NULL;
115 static int g_tree_script_pos = 0;
116
117 static char *g_list_script_buf = NULL;
118 static int g_list_script_pos = 0;
119
120 static char *g_part_list_buf = NULL;
121 static int g_part_list_pos = 0;
122
123 static int g_video_mode_max = 0;
124 static int g_video_mode_num = 0;
125 static ventoy_video_mode *g_video_mode_list = NULL;
126
127 static int g_enumerate_time_checked = 0;
128 static grub_uint64_t g_enumerate_start_time_ms;
129 static grub_uint64_t g_enumerate_finish_time_ms;
130 static int g_vtoy_file_flt[VTOY_FILE_FLT_BUTT] = {0};
131
132 static const char *g_menu_class[] =
133 {
134 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
135 };
136
137 static const char *g_menu_prefix[] =
138 {
139 "iso", "wim", "efi", "img", "vhd", "vtoy"
140 };
141
142 void ventoy_debug(const char *fmt, ...)
143 {
144 va_list args;
145
146 va_start (args, fmt);
147 grub_vprintf (fmt, args);
148 va_end (args);
149 }
150
151 void ventoy_debug_dump_guid(const char *prefix, grub_uint8_t *guid)
152 {
153 int i;
154
155 if (!g_ventoy_debug)
156 {
157 return;
158 }
159
160 debug("%s", prefix);
161 for (i = 0; i < 16; i++)
162 {
163 grub_printf("%02x ", guid[i]);
164 }
165 grub_printf("\n");
166 }
167
168 int ventoy_is_efi_os(void)
169 {
170 if (g_efi_os > 1)
171 {
172 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
173 }
174
175 return g_efi_os;
176 }
177
178 static int ventoy_get_fs_type(const char *fs)
179 {
180 if (NULL == fs)
181 {
182 return ventoy_fs_max;
183 }
184 else if (grub_strncmp(fs, "exfat", 5) == 0)
185 {
186 return ventoy_fs_exfat;
187 }
188 else if (grub_strncmp(fs, "ntfs", 4) == 0)
189 {
190 return ventoy_fs_ntfs;
191 }
192 else if (grub_strncmp(fs, "ext", 3) == 0)
193 {
194 return ventoy_fs_ext;
195 }
196 else if (grub_strncmp(fs, "xfs", 3) == 0)
197 {
198 return ventoy_fs_xfs;
199 }
200 else if (grub_strncmp(fs, "udf", 3) == 0)
201 {
202 return ventoy_fs_udf;
203 }
204 else if (grub_strncmp(fs, "fat", 3) == 0)
205 {
206 return ventoy_fs_fat;
207 }
208
209 return ventoy_fs_max;
210 }
211
212 static int ventoy_string_check(const char *str, grub_char_check_func check)
213 {
214 if (!str)
215 {
216 return 0;
217 }
218
219 for ( ; *str; str++)
220 {
221 if (!check(*str))
222 {
223 return 0;
224 }
225 }
226
227 return 1;
228 }
229
230
231 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
232 {
233 grub_memcpy(buf, (char *)file->data + file->offset, len);
234 return len;
235 }
236
237 static int ventoy_control_get_flag(const char *key)
238 {
239 const char *val = ventoy_get_env(key);
240
241 if (val && val[0] == '1' && val[1] == 0)
242 {
243 return 1;
244 }
245 return 0;
246 }
247
248 static grub_err_t ventoy_fs_close(grub_file_t file)
249 {
250 grub_file_close(g_old_file);
251 grub_free(file->data);
252
253 file->device = 0;
254 file->name = 0;
255
256 return 0;
257 }
258
259 static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg)
260 {
261 int i;
262
263 (void)hook_arg;
264
265 if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
266 {
267 return 0;
268 }
269
270 for (i = 0; i < g_video_mode_num; i++)
271 {
272 if (g_video_mode_list[i].width == info->width &&
273 g_video_mode_list[i].height == info->height &&
274 g_video_mode_list[i].bpp == info->bpp)
275 {
276 return 0;
277 }
278 }
279
280 g_video_mode_list[g_video_mode_num].width = info->width;
281 g_video_mode_list[g_video_mode_num].height = info->height;
282 g_video_mode_list[g_video_mode_num].bpp = info->bpp;
283 g_video_mode_num++;
284
285 if (g_video_mode_num == g_video_mode_max)
286 {
287 g_video_mode_max *= 2;
288 g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode));
289 }
290
291 return 0;
292 }
293
294 static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2)
295 {
296 if (v1->bpp == v2->bpp)
297 {
298 if (v1->width == v2->width)
299 {
300 if (v1->height == v2->height)
301 {
302 return 0;
303 }
304 else
305 {
306 return (v1->height < v2->height) ? -1 : 1;
307 }
308 }
309 else
310 {
311 return (v1->width < v2->width) ? -1 : 1;
312 }
313 }
314 else
315 {
316 return (v1->bpp < v2->bpp) ? -1 : 1;
317 }
318 }
319
320 static int ventoy_enum_video_mode(void)
321 {
322 int i, j;
323 grub_video_adapter_t adapter;
324 grub_video_driver_id_t id;
325 ventoy_video_mode mode;
326
327 g_video_mode_num = 0;
328 g_video_mode_max = 1024;
329 g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max);
330 if (!g_video_mode_list)
331 {
332 return 0;
333 }
334
335 #ifdef GRUB_MACHINE_PCBIOS
336 grub_dl_load ("vbe");
337 #endif
338
339 id = grub_video_get_driver_id ();
340
341 FOR_VIDEO_ADAPTERS (adapter)
342 {
343 if (!adapter->iterate ||
344 (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE ||
345 adapter->init() != GRUB_ERR_NONE)))
346 {
347 continue;
348 }
349
350 adapter->iterate(ventoy_video_hook, NULL);
351
352 if (adapter->id != id)
353 {
354 adapter->fini();
355 }
356 }
357
358 /* sort video mode */
359 for (i = 0; i < g_video_mode_num; i++)
360 for (j = i + 1; j < g_video_mode_num; j++)
361 {
362 if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0)
363 {
364 grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode));
365 grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode));
366 grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode));
367 }
368 }
369
370 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
371 }
372
373 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
374 {
375 int len;
376 grub_file_t file;
377 static struct grub_fs vtoy_fs =
378 {
379 .name = "vtoy",
380 .fs_dir = 0,
381 .fs_open = 0,
382 .fs_read = ventoy_fs_read,
383 .fs_close = ventoy_fs_close,
384 .fs_label = 0,
385 .next = 0
386 };
387
388 if (type != 52)
389 {
390 return rawFile;
391 }
392
393 file = (grub_file_t)grub_zalloc(sizeof (*file));
394 if (!file)
395 {
396 return 0;
397 }
398
399 file->data = grub_malloc(rawFile->size + 4096);
400 if (!file->data)
401 {
402 return 0;
403 }
404
405 grub_file_read(rawFile, file->data, rawFile->size);
406 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
407
408 g_old_file = rawFile;
409
410 file->size = rawFile->size + len;
411 file->device = rawFile->device;
412 file->fs = &vtoy_fs;
413 file->not_easily_seekable = 1;
414
415 return file;
416 }
417
418 static int ventoy_check_decimal_var(const char *name, long *value)
419 {
420 const char *value_str = NULL;
421
422 value_str = grub_env_get(name);
423 if (NULL == value_str)
424 {
425 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
426 }
427
428 if (!ventoy_is_decimal(value_str))
429 {
430 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
431 }
432
433 *value = grub_strtol(value_str, NULL, 10);
434
435 return GRUB_ERR_NONE;
436 }
437
438 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
439 {
440 if (argc != 1)
441 {
442 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
443 }
444
445 if (0 == grub_strcmp(args[0], "on"))
446 {
447 g_ventoy_debug = 1;
448 grub_env_set("vtdebug_flag", "debug");
449 }
450 else
451 {
452 g_ventoy_debug = 0;
453 grub_env_set("vtdebug_flag", "");
454 }
455
456 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
457 }
458
459 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
460 {
461 (void)ctxt;
462
463 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
464 {
465 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
466 grub_printf(" level:\r\n");
467 grub_printf(" 01/11: busybox / (+cat log)\r\n");
468 grub_printf(" 02/12: initrd / (+cat log)\r\n");
469 grub_printf(" 03/13: hook / (+cat log)\r\n");
470 grub_printf("\r\n");
471 grub_printf(" debug:\r\n");
472 grub_printf(" 0: debug is off\r\n");
473 grub_printf(" 1: debug is on\r\n");
474 grub_printf("\r\n");
475 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
476 }
477
478 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
479
480 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
481 {
482 g_ventoy_debug_level = 1;
483 }
484
485 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
486 }
487
488 static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
489 {
490 (void)ctxt;
491
492 if (argc != 2)
493 {
494 return 1;
495 }
496
497 return (grub_strstr(args[0], args[1])) ? 0 : 1;
498 }
499
500 static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
501 {
502 char *c0, *c1;
503
504 (void)ctxt;
505
506 if (argc != 2)
507 {
508 return 1;
509 }
510
511 c0 = args[0];
512 c1 = args[1];
513
514 while (*c0 && *c1)
515 {
516 if (*c0 != *c1)
517 {
518 return 1;
519 }
520 c0++;
521 c1++;
522 }
523
524 if (*c1)
525 {
526 return 1;
527 }
528
529 return 0;
530 }
531
532 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
533 {
534 long value_long = 0;
535 char buf[32];
536
537 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
538 {
539 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
540 }
541
542 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
543 {
544 return grub_errno;
545 }
546
547 value_long += grub_strtol(args[1], NULL, 10);
548
549 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
550 grub_env_set(args[0], buf);
551
552 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
553 }
554
555 static grub_err_t ventoy_cmd_mod(grub_extcmd_context_t ctxt, int argc, char **args)
556 {
557 ulonglong value1 = 0;
558 ulonglong value2 = 0;
559 char buf[32];
560
561 if (argc != 3)
562 {
563 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name);
564 }
565
566 value1 = grub_strtoull(args[0], NULL, 10);
567 value2 = grub_strtoull(args[1], NULL, 10);
568
569 grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1)));
570 grub_env_set(args[2], buf);
571
572 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
573 }
574
575 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
576 {
577 int rc = 1;
578 char buf[32];
579 grub_file_t file;
580
581 (void)ctxt;
582 (void)argc;
583 (void)args;
584
585 if (argc != 2)
586 {
587 return rc;
588 }
589
590 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
591 if (file == NULL)
592 {
593 debug("failed to open file <%s> for udf check\n", args[0]);
594 return 1;
595 }
596
597 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
598
599 grub_env_set(args[1], buf);
600
601 grub_file_close(file);
602 rc = 0;
603
604 return rc;
605 }
606
607 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
608 {
609 grub_file_t file;
610
611 (void)ctxt;
612 (void)argc;
613 (void)args;
614
615 g_wimboot_enable = 0;
616 grub_check_free(g_wimiso_path);
617 grub_check_free(g_wimiso_chunk_list.chunk);
618
619 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
620 if (!file)
621 {
622 return 0;
623 }
624
625 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
626 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
627 if (NULL == g_wimiso_chunk_list.chunk)
628 {
629 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
630 }
631
632 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
633 g_wimiso_chunk_list.cur_chunk = 0;
634
635 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
636
637 g_wimboot_enable = 1;
638 g_wimiso_path = grub_strdup(args[0]);
639
640 grub_file_close(file);
641
642 return 0;
643 }
644
645 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
646 {
647 int len;
648 grub_file_t file;
649 char exec[128];
650 char *data = NULL;
651 grub_uint32_t offset;
652
653 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
654 if (file == NULL)
655 {
656 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
657 return 1;
658 }
659
660 len = (int)file->size;
661
662 data = (char *)grub_malloc(file->size);
663 if (!data)
664 {
665 return 1;
666 }
667
668 grub_file_read(file, data, file->size);
669 grub_file_close(file);
670
671 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
672 grub_script_execute_sourcecode(exec);
673
674 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
675 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
676 grub_file_close(file);
677
678 grub_script_execute_sourcecode("loopback -d efiboot");
679
680 *buf = data;
681 *datalen = len;
682 *direntoff = offset + 2;
683
684 return 0;
685 }
686
687 static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
688 {
689 int len = 0;
690 int totlen = 0;
691 int offset = 0;
692 grub_file_t file;
693 char name[32];
694 char value[32];
695 char *buf = NULL;
696 char *data = NULL;
697 ventoy_iso9660_override *dirent;
698
699 (void)ctxt;
700
701 if (argc != 2)
702 {
703 return 1;
704 }
705
706 totlen = sizeof(ventoy_chain_head);
707
708 if (ventoy_load_efiboot_template(&buf, &len, &offset))
709 {
710 debug("failed to load efiboot template %d\n", len);
711 return 1;
712 }
713
714 totlen += len;
715
716 debug("efiboot template len:%d offset:%d\n", len, offset);
717
718 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
719 if (file == NULL)
720 {
721 debug("failed to open file <%s>\n", args[0]);
722 return 1;
723 }
724
725 totlen += ventoy_align_2k(file->size);
726
727 dirent = (ventoy_iso9660_override *)(buf + offset);
728 dirent->first_sector = len / 2048;
729 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
730 dirent->size = (grub_uint32_t)file->size;
731 dirent->size_be = grub_swap_bytes32(dirent->size);
732
733 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
734
735 #ifdef GRUB_MACHINE_EFI
736 data = (char *)grub_efi_allocate_iso_buf(totlen);
737 #else
738 data = (char *)grub_malloc(totlen);
739 #endif
740
741 ventoy_fill_os_param(file, (ventoy_os_param *)data);
742
743 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
744 grub_check_free(buf);
745
746 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
747 grub_file_close(file);
748
749 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
750 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
751 grub_env_set(name, value);
752
753 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
754 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
755 grub_env_set(name, value);
756
757 return 0;
758 }
759
760 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
761 {
762 int rc = 1;
763 char name[32];
764 char value[32];
765 char *buf = NULL;
766 grub_file_t file;
767
768 (void)ctxt;
769 (void)argc;
770 (void)args;
771
772 if (argc != 2)
773 {
774 return rc;
775 }
776
777 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
778 if (file == NULL)
779 {
780 debug("failed to open file <%s>\n", args[0]);
781 return 1;
782 }
783
784 #ifdef GRUB_MACHINE_EFI
785 buf = (char *)grub_efi_allocate_iso_buf(file->size);
786 #else
787 buf = (char *)grub_malloc(file->size);
788 #endif
789
790 grub_file_read(file, buf, file->size);
791
792 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
793 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
794 grub_env_set(name, value);
795
796 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
797 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
798 grub_env_set(name, value);
799
800 grub_file_close(file);
801 rc = 0;
802
803 return rc;
804 }
805
806 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
807 {
808 int rc = 1;
809 int headlen;
810 char name[32];
811 char value[32];
812 char *buf = NULL;
813 grub_file_t file;
814
815 (void)ctxt;
816 (void)argc;
817 (void)args;
818
819 if (argc != 2)
820 {
821 return rc;
822 }
823
824 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
825 if (file == NULL)
826 {
827 debug("failed to open file <%s> for udf check\n", args[0]);
828 return 1;
829 }
830
831 headlen = sizeof(ventoy_chain_head);
832
833 #ifdef GRUB_MACHINE_EFI
834 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
835 #else
836 buf = (char *)grub_malloc(headlen + file->size);
837 #endif
838
839 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
840
841 grub_file_read(file, buf + headlen, file->size);
842
843 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
844 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
845 grub_env_set(name, value);
846
847 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
848 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
849 grub_env_set(name, value);
850
851 grub_file_close(file);
852 rc = 0;
853
854 return rc;
855 }
856
857 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
858 {
859 (void)ctxt;
860
861 if (argc != 1)
862 {
863 return 1;
864 }
865
866 if (args[0][0] == '1')
867 {
868 grub_iso9660_set_nojoliet(1);
869 }
870 else
871 {
872 grub_iso9660_set_nojoliet(0);
873 }
874
875 return 0;
876 }
877
878 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
879 {
880 int i;
881 int rc = 1;
882 grub_file_t file;
883 grub_uint8_t buf[32];
884
885 (void)ctxt;
886 (void)argc;
887 (void)args;
888
889 if (argc != 1)
890 {
891 return rc;
892 }
893
894 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
895 if (file == NULL)
896 {
897 debug("failed to open file <%s> for udf check\n", args[0]);
898 return 1;
899 }
900
901 for (i = 16; i < 32; i++)
902 {
903 grub_file_seek(file, i * 2048);
904 grub_file_read(file, buf, sizeof(buf));
905 if (buf[0] == 255)
906 {
907 break;
908 }
909 }
910
911 i++;
912 grub_file_seek(file, i * 2048);
913 grub_file_read(file, buf, sizeof(buf));
914
915 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
916 {
917 i++;
918 grub_file_seek(file, i * 2048);
919 grub_file_read(file, buf, sizeof(buf));
920
921 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
922 grub_memcmp(buf + 1, "NSR03", 5) == 0)
923 {
924 rc = 0;
925 }
926 }
927
928 grub_file_close(file);
929
930 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
931
932 return rc;
933 }
934
935 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
936 {
937 long value_long1 = 0;
938 long value_long2 = 0;
939
940 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
941 {
942 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
943 }
944
945 value_long1 = grub_strtol(args[0], NULL, 10);
946 value_long2 = grub_strtol(args[2], NULL, 10);
947
948 if (0 == grub_strcmp(args[1], "eq"))
949 {
950 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
951 }
952 else if (0 == grub_strcmp(args[1], "ne"))
953 {
954 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
955 }
956 else if (0 == grub_strcmp(args[1], "gt"))
957 {
958 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
959 }
960 else if (0 == grub_strcmp(args[1], "lt"))
961 {
962 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
963 }
964 else if (0 == grub_strcmp(args[1], "ge"))
965 {
966 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
967 }
968 else if (0 == grub_strcmp(args[1], "le"))
969 {
970 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
971 }
972 else
973 {
974 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
975 }
976
977 return grub_errno;
978 }
979
980 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
981 {
982 char *pos = NULL;
983 char buf[128] = {0};
984
985 if (argc != 2)
986 {
987 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
988 }
989
990 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
991 pos = grub_strstr(buf, ",");
992 if (pos)
993 {
994 *pos = 0;
995 }
996
997 grub_env_set(args[1], buf);
998
999 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1000 }
1001
1002 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
1003 {
1004 int i;
1005 char buf[256];
1006 grub_disk_t disk;
1007 char *pos = NULL;
1008 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
1009
1010 (void)ctxt;
1011
1012 if (argc != 1)
1013 {
1014 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
1015 }
1016
1017 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
1018 {
1019 grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]);
1020 if (0 == grub_script_execute_sourcecode(buf))
1021 {
1022 debug("file %s exist, ventoy_compatible YES\n", buf);
1023 grub_env_set("ventoy_compatible", "YES");
1024 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1025 }
1026 else
1027 {
1028 debug("file %s NOT exist\n", buf);
1029 }
1030 }
1031
1032 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
1033 pos = grub_strstr(buf, ")");
1034 if (pos)
1035 {
1036 *pos = 0;
1037 }
1038
1039 disk = grub_disk_open(buf);
1040 if (disk)
1041 {
1042 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
1043 grub_disk_close(disk);
1044
1045 g_img_swap_tmp_buf[703] = 0;
1046 for (i = 318; i < 703; i++)
1047 {
1048 if (g_img_swap_tmp_buf[i] == 'V' &&
1049 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
1050 {
1051 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
1052 grub_env_set("ventoy_compatible", "YES");
1053 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1054 }
1055 }
1056 }
1057 else
1058 {
1059 debug("failed to open disk <%s>\n", buf);
1060 }
1061
1062 grub_env_set("ventoy_compatible", "NO");
1063 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1064 }
1065
1066 int ventoy_cmp_img(img_info *img1, img_info *img2)
1067 {
1068 char *s1, *s2;
1069 int c1 = 0;
1070 int c2 = 0;
1071
1072 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1073 {
1074 return (img1->plugin_list_index - img2->plugin_list_index);
1075 }
1076
1077 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1078 {
1079 c1 = *s1;
1080 c2 = *s2;
1081
1082 if (0 == g_sort_case_sensitive)
1083 {
1084 if (grub_islower(c1))
1085 {
1086 c1 = c1 - 'a' + 'A';
1087 }
1088
1089 if (grub_islower(c2))
1090 {
1091 c2 = c2 - 'a' + 'A';
1092 }
1093 }
1094
1095 if (c1 != c2)
1096 {
1097 break;
1098 }
1099 }
1100
1101 return (c1 - c2);
1102 }
1103
1104 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1105 {
1106 char *s1, *s2;
1107 int c1 = 0;
1108 int c2 = 0;
1109
1110 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1111 {
1112 return (node1->plugin_list_index - node2->plugin_list_index);
1113 }
1114
1115 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1116 {
1117 c1 = *s1;
1118 c2 = *s2;
1119
1120 if (0 == g_sort_case_sensitive)
1121 {
1122 if (grub_islower(c1))
1123 {
1124 c1 = c1 - 'a' + 'A';
1125 }
1126
1127 if (grub_islower(c2))
1128 {
1129 c2 = c2 - 'a' + 'A';
1130 }
1131 }
1132
1133 if (c1 != c2)
1134 {
1135 break;
1136 }
1137 }
1138
1139 return (c1 - c2);
1140 }
1141
1142 void ventoy_swap_img(img_info *img1, img_info *img2)
1143 {
1144 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1145
1146 grub_memcpy(img1, img2, sizeof(img_info));
1147 img1->next = g_img_swap_tmp.next;
1148 img1->prev = g_img_swap_tmp.prev;
1149
1150 g_img_swap_tmp.next = img2->next;
1151 g_img_swap_tmp.prev = img2->prev;
1152 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1153 }
1154
1155 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1156 {
1157 (void)namelen;
1158
1159 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1160 {
1161 return 0;
1162 }
1163
1164 return 1;
1165 }
1166
1167 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
1168 {
1169 if (0 == info->dir)
1170 {
1171 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
1172 {
1173 *((int *)data) = 1;
1174 return 0;
1175 }
1176 }
1177
1178 return 0;
1179 }
1180
1181 static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1182 {
1183 //int i = 0;
1184 int type = 0;
1185 int ignore = 0;
1186 int index = 0;
1187 grub_size_t len;
1188 img_info *img;
1189 img_info *tail;
1190 img_iterator_node *tmp;
1191 img_iterator_node *new_node;
1192 img_iterator_node *node = (img_iterator_node *)data;
1193
1194 if (g_enumerate_time_checked == 0)
1195 {
1196 g_enumerate_finish_time_ms = grub_get_time_ms();
1197 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1198 {
1199 grub_cls();
1200 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1201 grub_refresh();
1202 g_enumerate_time_checked = 1;
1203 }
1204 }
1205
1206 len = grub_strlen(filename);
1207
1208 if (info->dir)
1209 {
1210 if (node->level + 1 > g_img_max_search_level)
1211 {
1212 return 0;
1213 }
1214
1215 if ((len == 1 && filename[0] == '.') ||
1216 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1217 {
1218 return 0;
1219 }
1220
1221 if (!ventoy_img_name_valid(filename, len))
1222 {
1223 return 0;
1224 }
1225
1226 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1227 {
1228 return 0;
1229 }
1230
1231 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1232 {
1233 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1234 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1235 if (index == 0)
1236 {
1237 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1238 return 0;
1239 }
1240 }
1241
1242 new_node = grub_zalloc(sizeof(img_iterator_node));
1243 if (new_node)
1244 {
1245 new_node->level = node->level + 1;
1246 new_node->plugin_list_index = index;
1247 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1248
1249 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1250 if (ignore)
1251 {
1252 debug("Directory %s ignored...\n", new_node->dir);
1253 grub_free(new_node);
1254 return 0;
1255 }
1256
1257 new_node->tail = node->tail;
1258
1259 new_node->parent = node;
1260 if (!node->firstchild)
1261 {
1262 node->firstchild = new_node;
1263 }
1264
1265 if (g_img_iterator_tail)
1266 {
1267 g_img_iterator_tail->next = new_node;
1268 g_img_iterator_tail = new_node;
1269 }
1270 else
1271 {
1272 g_img_iterator_head.next = new_node;
1273 g_img_iterator_tail = new_node;
1274 }
1275 }
1276 }
1277 else
1278 {
1279 debug("Find a file %s\n", filename);
1280 if (len < 4)
1281 {
1282 return 0;
1283 }
1284
1285 if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso"))
1286 {
1287 type = img_type_iso;
1288 }
1289 else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1290 {
1291 type = img_type_wim;
1292 }
1293 else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1294 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1295 {
1296 type = img_type_vhd;
1297 }
1298 #ifdef GRUB_MACHINE_EFI
1299 else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi"))
1300 {
1301 type = img_type_efi;
1302 }
1303 #endif
1304 else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img"))
1305 {
1306 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1307 {
1308 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1309 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1310 {
1311 return 0;
1312 }
1313 }
1314 type = img_type_img;
1315 }
1316 else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1317 {
1318 type = img_type_vtoy;
1319 }
1320 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1321 {
1322 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1323 {
1324 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1325 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1326 }
1327 return 0;
1328 }
1329 else
1330 {
1331 return 0;
1332 }
1333
1334 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1335 {
1336 return 0;
1337 }
1338
1339 if (g_plugin_image_list)
1340 {
1341 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1342 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1343 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1344 {
1345 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1346 return 0;
1347 }
1348 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
1349 {
1350 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index);
1351 return 0;
1352 }
1353 }
1354
1355 img = grub_zalloc(sizeof(img_info));
1356 if (img)
1357 {
1358 img->type = type;
1359 img->plugin_list_index = index;
1360 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1361
1362 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1363
1364 img->size = info->size;
1365 if (0 == img->size)
1366 {
1367 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1368 }
1369
1370 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1371 {
1372 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1373 grub_free(img);
1374 return 0;
1375 }
1376
1377 if (g_ventoy_img_list)
1378 {
1379 tail = *(node->tail);
1380 img->prev = tail;
1381 tail->next = img;
1382 }
1383 else
1384 {
1385 g_ventoy_img_list = img;
1386 }
1387
1388 img->id = g_ventoy_img_count;
1389 img->parent = node;
1390 if (node && NULL == node->firstiso)
1391 {
1392 node->firstiso = img;
1393 }
1394
1395 node->isocnt++;
1396 tmp = node->parent;
1397 while (tmp)
1398 {
1399 tmp->isocnt++;
1400 tmp = tmp->parent;
1401 }
1402
1403 *((img_info **)(node->tail)) = img;
1404 g_ventoy_img_count++;
1405
1406 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1407 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1408 if (!img->class)
1409 {
1410 img->class = g_menu_class[type];
1411 }
1412 img->menu_prefix = g_menu_prefix[type];
1413
1414 if (img_type_iso == type)
1415 {
1416 if (ventoy_plugin_check_memdisk(img->path))
1417 {
1418 img->menu_prefix = "miso";
1419 }
1420 }
1421
1422 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1423 }
1424 }
1425
1426 return 0;
1427 }
1428
1429 static int ventoy_arch_mode_init(void)
1430 {
1431 #ifdef GRUB_MACHINE_EFI
1432 if (grub_strcmp(GRUB_TARGET_CPU, "i386") == 0)
1433 {
1434 g_ventoy_plat_data = VTOY_PLAT_I386_UEFI;
1435 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "ia32");
1436 }
1437 else if (grub_strcmp(GRUB_TARGET_CPU, "arm64") == 0)
1438 {
1439 g_ventoy_plat_data = VTOY_PLAT_ARM64_UEFI;
1440 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "aa64");
1441 }
1442 else if (grub_strcmp(GRUB_TARGET_CPU, "mips64el") == 0)
1443 {
1444 g_ventoy_plat_data = VTOY_PLAT_MIPS_UEFI;
1445 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "mips");
1446 }
1447 else
1448 {
1449 g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI;
1450 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi");
1451 }
1452 #else
1453 g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY;
1454 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy");
1455 #endif
1456
1457 return 0;
1458 }
1459
1460 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1461 {
1462 int len = GRUB_UINT_MAX;
1463 const char *value = NULL;
1464 char name[32] = {0};
1465 char plat[32] = {0};
1466 char guidstr[32] = {0};
1467 ventoy_guid guid = VENTOY_GUID;
1468 const char *fmt1 = NULL;
1469 const char *fmt2 = NULL;
1470 const char *fmt3 = NULL;
1471 grub_uint32_t *puint = (grub_uint32_t *)name;
1472 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1473 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1474 const char fmtcode[]={
1475 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1476 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1477 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1478 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1479 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1480 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1481 };
1482
1483 grub_memset(name, 0, sizeof(name));
1484 puint[0] = grub_swap_bytes32(0x56454e54);
1485 puint[3] = grub_swap_bytes32(0x4f4e0000);
1486 puint[2] = grub_swap_bytes32(0x45525349);
1487 puint[1] = grub_swap_bytes32(0x4f595f56);
1488 value = ventoy_get_env(name);
1489
1490 grub_memset(name, 0, sizeof(name));
1491 puint[1] = grub_swap_bytes32(0x5f544f50);
1492 puint[0] = grub_swap_bytes32(0x56544c45);
1493 fmt1 = ventoy_get_env(name);
1494 if (!fmt1)
1495 {
1496 fmt1 = fmtdata;
1497 }
1498
1499 grub_memset(name, 0, sizeof(name));
1500 puint[1] = grub_swap_bytes32(0x5f4c4654);
1501 puint[0] = grub_swap_bytes32(0x56544c45);
1502 fmt2 = ventoy_get_env(name);
1503
1504 grub_memset(name, 0, sizeof(name));
1505 puint[1] = grub_swap_bytes32(0x5f434c52);
1506 puint[0] = grub_swap_bytes32(0x56544c45);
1507 fmt3 = ventoy_get_env(name);
1508
1509 grub_memcpy(guidstr, &guid, sizeof(guid));
1510
1511 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1512
1513 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1514 #pragma GCC diagnostic push
1515 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1516 len = grub_snprintf(buffer, buflen, fmtcode,
1517 fmt1 ? fmt1 : fmtdata,
1518 fmt2 ? fmt2 : fmtdata + 4,
1519 value ? value : "", plat, guidstr,
1520 fmt3 ? fmt3 : fmtdata + 6);
1521 #pragma GCC diagnostic pop
1522
1523 grub_memset(name, 0, sizeof(name));
1524 puint[0] = grub_swap_bytes32(0x76746f79);
1525 puint[2] = grub_swap_bytes32(0x656e7365);
1526 puint[1] = grub_swap_bytes32(0x5f6c6963);
1527 ventoy_set_env(name, guidstr);
1528
1529 return len;
1530 }
1531
1532 int ventoy_check_password(const vtoy_password *pwd, int retry)
1533 {
1534 int offset;
1535 char input[256];
1536 grub_uint8_t md5[16];
1537
1538 while (retry--)
1539 {
1540 grub_memset(input, 0, sizeof(input));
1541
1542 grub_printf("Enter password: ");
1543 grub_refresh();
1544
1545 if (pwd->type == VTOY_PASSWORD_TXT)
1546 {
1547 grub_password_get(input, 128);
1548 if (grub_strcmp(pwd->text, input) == 0)
1549 {
1550 return 0;
1551 }
1552 }
1553 else if (pwd->type == VTOY_PASSWORD_MD5)
1554 {
1555 grub_password_get(input, 128);
1556 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1557 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1558 {
1559 return 0;
1560 }
1561 }
1562 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1563 {
1564 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1565 grub_password_get(input + offset, 128);
1566
1567 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1568 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1569 {
1570 return 0;
1571 }
1572 }
1573
1574 grub_printf("Invalid password!\n\n");
1575 grub_refresh();
1576 }
1577
1578 return 1;
1579 }
1580
1581 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1582 {
1583 img_info *minimg = NULL;
1584 img_info *img = (img_info *)(node->firstiso);
1585
1586 while (img && (img_iterator_node *)(img->parent) == node)
1587 {
1588 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1589 {
1590 minimg = img;
1591 }
1592 img = img->next;
1593 }
1594
1595 if (minimg)
1596 {
1597 minimg->select = 1;
1598 }
1599
1600 return minimg;
1601 }
1602
1603 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1604 {
1605 img_iterator_node *Minchild = NULL;
1606 img_iterator_node *child = node->firstchild;
1607
1608 while (child && child->parent == node)
1609 {
1610 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1611 {
1612 Minchild = child;
1613 }
1614 child = child->next;
1615 }
1616
1617 if (Minchild)
1618 {
1619 Minchild->select = 1;
1620 }
1621
1622 return Minchild;
1623 }
1624
1625 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1626 {
1627 int offset = 1;
1628 img_info *img = NULL;
1629 const char *dir_class = NULL;
1630 const char *dir_alias = NULL;
1631 img_iterator_node *child = NULL;
1632
1633 if (node->isocnt == 0 || node->done == 1)
1634 {
1635 return 0;
1636 }
1637
1638 if (node->parent && node->parent->dirlen < node->dirlen)
1639 {
1640 offset = node->parent->dirlen;
1641 }
1642
1643 if (node == &g_img_iterator_head)
1644 {
1645 if (g_default_menu_mode == 0)
1646 {
1647 if (g_tree_view_menu_style == 0)
1648 {
1649 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1650 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1651 " echo 'return ...' \n"
1652 "}\n", "<--");
1653 }
1654 else
1655 {
1656 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1657 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1658 " echo '%s ...' \n"
1659 "}\n", "return");
1660 }
1661 }
1662 }
1663 else
1664 {
1665 node->dir[node->dirlen - 1] = 0;
1666 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1667 if (!dir_class)
1668 {
1669 dir_class = "vtoydir";
1670 }
1671
1672 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1673 if (dir_alias)
1674 {
1675 if (g_tree_view_menu_style == 0)
1676 {
1677 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1678 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1679 "DIR", dir_alias, dir_class, node->dir + offset);
1680 }
1681 else
1682 {
1683 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1684 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1685 dir_alias, dir_class, node->dir + offset);
1686 }
1687 }
1688 else
1689 {
1690 dir_alias = node->dir + offset;
1691
1692 if (g_tree_view_menu_style == 0)
1693 {
1694 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1695 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1696 "DIR", dir_alias, dir_class, node->dir + offset);
1697 }
1698 else
1699 {
1700 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1701 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1702 dir_alias, dir_class, node->dir + offset);
1703 }
1704 }
1705
1706 if (g_tree_view_menu_style == 0)
1707 {
1708 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1709 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1710 " echo 'return ...' \n"
1711 "}\n", "<--");
1712 }
1713 else
1714 {
1715 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1716 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1717 " echo '%s ...' \n"
1718 "}\n", "return");
1719 }
1720 }
1721
1722 while ((child = ventoy_get_min_child(node)) != NULL)
1723 {
1724 ventoy_dynamic_tree_menu(child);
1725 }
1726
1727 while ((img = ventoy_get_min_iso(node)) != NULL)
1728 {
1729 if (g_tree_view_menu_style == 0)
1730 {
1731 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1732 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1733 " %s_%s \n"
1734 "}\n",
1735 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1736 img->unsupport ? "[***********] " : "",
1737 img->alias ? img->alias : img->name, img->class, img->id,
1738 img->menu_prefix,
1739 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1740 }
1741 else
1742 {
1743 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1744 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1745 " %s_%s \n"
1746 "}\n",
1747 img->unsupport ? "[***********] " : "",
1748 img->alias ? img->alias : img->name, img->class, img->id,
1749 img->menu_prefix,
1750 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1751 }
1752 }
1753
1754 if (node != &g_img_iterator_head)
1755 {
1756 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1757 }
1758
1759 node->done = 1;
1760 return 0;
1761 }
1762
1763 int ventoy_check_device_result(int ret)
1764 {
1765 char buf[32];
1766
1767 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1768 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1769 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1770
1771 if (ret)
1772 {
1773 grub_printf(VTOY_WARNING"\n");
1774 grub_printf(VTOY_WARNING"\n");
1775 grub_printf(VTOY_WARNING"\n\n\n");
1776
1777 grub_printf("This is NOT a standard Ventoy device and is NOT supported (0x%x).\n\n", ret);
1778 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1779
1780 grub_printf("\n\nWill exit after 10 seconds ...... ");
1781 grub_refresh();
1782 grub_sleep(10);
1783 }
1784
1785 return ret;
1786 }
1787
1788 int ventoy_check_device(grub_device_t dev)
1789 {
1790 int workaround = 0;
1791 grub_file_t file;
1792 grub_uint64_t offset;
1793 char devname[64];
1794 grub_fs_t fs;
1795 grub_device_t dev2;
1796 char *label = NULL;
1797 struct grub_partition *partition;
1798
1799 if (dev->disk == NULL || dev->disk->partition == NULL)
1800 {
1801 return ventoy_check_device_result(1 | 0x1000);
1802 }
1803
1804 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1805 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1806 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1807 {
1808 #ifndef GRUB_MACHINE_EFI
1809 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
1810 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
1811 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1812 {
1813 return ventoy_check_device_result(2 | 0x1000);
1814 }
1815 else
1816 {
1817 workaround = 1;
1818 }
1819 #endif
1820 }
1821
1822 /* We must have partition 2 */
1823 if (workaround)
1824 {
1825 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1826 }
1827 else
1828 {
1829 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1830 }
1831 if (!file)
1832 {
1833 return ventoy_check_device_result(3 | 0x1000);
1834 }
1835
1836 if (NULL == grub_strstr(file->fs->name, "fat"))
1837 {
1838 grub_file_close(file);
1839 return ventoy_check_device_result(4 | 0x1000);
1840 }
1841
1842 partition = dev->disk->partition;
1843 if (partition->number != 0 || partition->start != 2048)
1844 {
1845 return ventoy_check_device_result(5);
1846 }
1847
1848 if (workaround)
1849 {
1850 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
1851 {
1852 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
1853 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
1854 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
1855 {
1856 grub_file_close(file);
1857 return ventoy_check_device_result(6);
1858 }
1859 }
1860 else
1861 {
1862 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
1863 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
1864 PartTbl[1].SectorCount != 65536)
1865 {
1866 grub_file_close(file);
1867 return ventoy_check_device_result(6);
1868 }
1869 }
1870 }
1871 else
1872 {
1873 offset = partition->start + partition->len;
1874 partition = file->device->disk->partition;
1875 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1876 {
1877 grub_file_close(file);
1878 return ventoy_check_device_result(7);
1879 }
1880 }
1881
1882 grub_file_close(file);
1883
1884 if (workaround == 0)
1885 {
1886 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1887 dev2 = grub_device_open(devname);
1888 if (!dev2)
1889 {
1890 return ventoy_check_device_result(8);
1891 }
1892
1893 fs = grub_fs_probe(dev2);
1894 if (!fs)
1895 {
1896 grub_device_close(dev2);
1897 return ventoy_check_device_result(9);
1898 }
1899
1900 fs->fs_label(dev2, &label);
1901 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1902 {
1903 grub_device_close(dev2);
1904 return ventoy_check_device_result(10);
1905 }
1906
1907 grub_device_close(dev2);
1908 }
1909
1910 return ventoy_check_device_result(0);
1911 }
1912
1913 static int ventoy_set_default_menu(void)
1914 {
1915 int img_len = 0;
1916 char *pos = NULL;
1917 char *end = NULL;
1918 char *def = NULL;
1919 const char *strdata = NULL;
1920 img_info *cur = NULL;
1921 img_info *default_node = NULL;
1922 const char *default_image = NULL;
1923
1924 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1925 if (default_image && default_image[0] == '/')
1926 {
1927 img_len = grub_strlen(default_image);
1928
1929 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1930 {
1931 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1932 {
1933 default_node = cur;
1934 break;
1935 }
1936 }
1937
1938 if (!default_node)
1939 {
1940 return 1;
1941 }
1942
1943 if (0 == g_default_menu_mode)
1944 {
1945 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1946 }
1947 else
1948 {
1949 def = grub_strdup(default_image);
1950 if (!def)
1951 {
1952 return 1;
1953 }
1954
1955 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1956
1957 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1958 if (strdata && strdata[0] == '/')
1959 {
1960 pos = def + grub_strlen(strdata);
1961 if (*pos == '/')
1962 {
1963 pos++;
1964 }
1965 }
1966 else
1967 {
1968 pos = def + 1;
1969 }
1970
1971 while ((end = grub_strchr(pos, '/')) != NULL)
1972 {
1973 *end = 0;
1974 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1975 pos = end + 1;
1976 }
1977
1978 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1979 grub_free(def);
1980 }
1981 }
1982
1983 return 0;
1984 }
1985
1986 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1987 {
1988 int len;
1989 grub_fs_t fs;
1990 grub_device_t dev = NULL;
1991 img_info *cur = NULL;
1992 img_info *tail = NULL;
1993 const char *strdata = NULL;
1994 char *device_name = NULL;
1995 char buf[32];
1996 img_iterator_node *node = NULL;
1997 img_iterator_node *tmp = NULL;
1998
1999 (void)ctxt;
2000
2001 if (argc != 2)
2002 {
2003 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2004 }
2005
2006 if (g_ventoy_img_list || g_ventoy_img_count)
2007 {
2008 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2009 }
2010
2011 g_enumerate_time_checked = 0;
2012 g_enumerate_start_time_ms = grub_get_time_ms();
2013
2014 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2015 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2016 {
2017 g_filt_dot_underscore_file = 1;
2018 }
2019
2020 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2021 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2022 {
2023 g_sort_case_sensitive = 1;
2024 }
2025
2026 device_name = grub_file_get_device_name(args[0]);
2027 if (!device_name)
2028 {
2029 goto fail;
2030 }
2031
2032 g_enum_dev = dev = grub_device_open(device_name);
2033 if (!dev)
2034 {
2035 goto fail;
2036 }
2037
2038 g_enum_fs = fs = grub_fs_probe(dev);
2039 if (!fs)
2040 {
2041 goto fail;
2042 }
2043
2044 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2045 {
2046 debug("unsupported fs:<%s>\n", fs->name);
2047 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2048 goto fail;
2049 }
2050
2051 ventoy_set_env("vtoy_iso_fs", fs->name);
2052
2053 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2054 if (strdata && strdata[0] == '1')
2055 {
2056 g_default_menu_mode = 1;
2057 }
2058
2059 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2060
2061 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2062
2063 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2064 if (strdata && strdata[0] == '/')
2065 {
2066 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2067 if (g_img_iterator_head.dir[len - 1] != '/')
2068 {
2069 g_img_iterator_head.dir[len++] = '/';
2070 }
2071 g_img_iterator_head.dirlen = len;
2072 }
2073 else
2074 {
2075 g_img_iterator_head.dirlen = 1;
2076 grub_strcpy(g_img_iterator_head.dir, "/");
2077 }
2078
2079 g_img_iterator_head.tail = &tail;
2080
2081 if (g_img_max_search_level < 0)
2082 {
2083 g_img_max_search_level = GRUB_INT_MAX;
2084 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2085 if (strdata && ventoy_is_decimal(strdata))
2086 {
2087 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2088 }
2089 }
2090
2091 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2092 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2093 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2094 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2095 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2096 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2097
2098 for (node = &g_img_iterator_head; node; node = node->next)
2099 {
2100 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2101 }
2102
2103 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2104 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2105 {
2106 g_tree_view_menu_style = 1;
2107 }
2108
2109 ventoy_set_default_menu();
2110
2111 for (node = &g_img_iterator_head; node; node = node->next)
2112 {
2113 ventoy_dynamic_tree_menu(node);
2114 }
2115
2116 /* free node */
2117 node = g_img_iterator_head.next;
2118 while (node)
2119 {
2120 tmp = node->next;
2121 grub_free(node);
2122 node = tmp;
2123 }
2124
2125 /* sort image list by image name */
2126 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2127 {
2128 for (tail = cur->next; tail; tail = tail->next)
2129 {
2130 if (ventoy_cmp_img(cur, tail) > 0)
2131 {
2132 ventoy_swap_img(cur, tail);
2133 }
2134 }
2135 }
2136
2137 if (g_default_menu_mode == 1)
2138 {
2139 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2140 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2141 " echo 'return ...' \n"
2142 "}\n", "<--");
2143 }
2144
2145 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2146 {
2147 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2148 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2149 " %s_%s \n"
2150 "}\n",
2151 cur->unsupport ? "[***********] " : "",
2152 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2153 cur->menu_prefix,
2154 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2155 }
2156
2157 g_tree_script_buf[g_tree_script_pos] = 0;
2158 g_list_script_buf[g_list_script_pos] = 0;
2159
2160 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2161 grub_env_set(args[1], buf);
2162
2163 fail:
2164
2165 check_free(device_name, grub_free);
2166 check_free(dev, grub_device_close);
2167
2168 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2169 }
2170
2171
2172 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2173 {
2174 img_info *next = NULL;
2175 img_info *cur = g_ventoy_img_list;
2176
2177 (void)ctxt;
2178 (void)argc;
2179 (void)args;
2180
2181 while (cur)
2182 {
2183 next = cur->next;
2184 grub_free(cur);
2185 cur = next;
2186 }
2187
2188 g_ventoy_img_list = NULL;
2189 g_ventoy_img_count = 0;
2190
2191 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2192 }
2193
2194 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2195 {
2196 long img_id = 0;
2197 img_info *cur = g_ventoy_img_list;
2198
2199 (void)ctxt;
2200
2201 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2202 {
2203 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2204 }
2205
2206 img_id = grub_strtol(args[0], NULL, 10);
2207 if (img_id >= g_ventoy_img_count)
2208 {
2209 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2210 }
2211
2212 debug("Find image %ld name \n", img_id);
2213
2214 while (cur && img_id > 0)
2215 {
2216 img_id--;
2217 cur = cur->next;
2218 }
2219
2220 if (!cur)
2221 {
2222 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2223 }
2224
2225 debug("image name is %s\n", cur->name);
2226
2227 grub_env_set(args[1], cur->name);
2228
2229 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2230 }
2231
2232 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2233 {
2234 int len = 0;
2235 char id[32] = {0};
2236 img_info *cur = g_ventoy_img_list;
2237
2238 (void)ctxt;
2239
2240 if (argc != 1)
2241 {
2242 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2243 }
2244
2245 len = (int)grub_strlen(args[0]);
2246
2247 while (cur)
2248 {
2249 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2250 {
2251 break;
2252 }
2253 cur = cur->next;
2254 }
2255
2256 if (!cur)
2257 {
2258 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2259 }
2260
2261 grub_snprintf(id, sizeof(id), "VID_%d", cur->id);
2262 grub_env_set("chosen", id);
2263 grub_env_export("chosen");
2264
2265 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2266 }
2267
2268 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2269 {
2270 int img_id = 0;
2271 char value[32];
2272 char *pos = NULL;
2273 const char *id = NULL;
2274 img_info *cur = g_ventoy_img_list;
2275
2276 (void)ctxt;
2277
2278 if (argc < 1 || argc > 2)
2279 {
2280 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2281 }
2282
2283 id = grub_env_get("chosen");
2284
2285 pos = grub_strstr(id, "VID_");
2286 if (pos)
2287 {
2288 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2289 }
2290 else
2291 {
2292 img_id = (int)grub_strtoul(id, NULL, 10);
2293 }
2294
2295 while (cur)
2296 {
2297 if (img_id == cur->id)
2298 {
2299 break;
2300 }
2301 cur = cur->next;
2302 }
2303
2304 if (!cur)
2305 {
2306 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2307 }
2308
2309 grub_env_set(args[0], cur->path);
2310
2311 if (argc > 1)
2312 {
2313 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2314 grub_env_set(args[1], value);
2315 }
2316
2317 g_svd_replace_offset = 0;
2318
2319 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2320 }
2321
2322 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2323 {
2324 grub_disk_t disk;
2325 char *device_name;
2326 char *pos;
2327 char *pos2;
2328
2329 device_name = grub_file_get_device_name(filename);
2330 if (!device_name)
2331 {
2332 return 1;
2333 }
2334
2335 pos = device_name;
2336 if (pos[0] == '(')
2337 {
2338 pos++;
2339 }
2340
2341 pos2 = grub_strstr(pos, ",");
2342 if (!pos2)
2343 {
2344 pos2 = grub_strstr(pos, ")");
2345 }
2346
2347 if (pos2)
2348 {
2349 *pos2 = 0;
2350 }
2351
2352 disk = grub_disk_open(pos);
2353 if (disk)
2354 {
2355 grub_disk_read(disk, 0, 0x180, 16, guid);
2356 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2357 grub_disk_close(disk);
2358 }
2359 else
2360 {
2361 return 1;
2362 }
2363
2364 grub_free(device_name);
2365 return 0;
2366 }
2367
2368 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2369 {
2370 eltorito_descriptor desc;
2371
2372 grub_memset(&desc, 0, sizeof(desc));
2373 grub_file_seek(file, 17 * 2048);
2374 grub_file_read(file, &desc, sizeof(desc));
2375
2376 if (desc.type != 0 || desc.version != 1)
2377 {
2378 return 0;
2379 }
2380
2381 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2382 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2383 {
2384 return 0;
2385 }
2386
2387 return desc.sector;
2388 }
2389
2390 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2391 {
2392 int i;
2393 int x86count = 0;
2394 grub_uint8_t buf[512];
2395 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2396
2397 grub_file_seek(file, sector * 2048);
2398 grub_file_read(file, buf, sizeof(buf));
2399
2400 if (buf[0] == 0x01 && buf[1] == 0xEF)
2401 {
2402 debug("%s efi eltorito in Validation Entry\n", file->name);
2403 return 1;
2404 }
2405
2406 if (buf[0] == 0x01 && buf[1] == 0x00)
2407 {
2408 x86count++;
2409 }
2410
2411 for (i = 64; i < (int)sizeof(buf); i += 32)
2412 {
2413 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2414 {
2415 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2416 return 1;
2417 }
2418
2419 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2420 {
2421 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2422 return 1;
2423 }
2424 }
2425
2426 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2427 {
2428 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2429 {
2430 if (buf[36] == parttype[i])
2431 {
2432 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2433 return 1;
2434 }
2435 }
2436 }
2437
2438 debug("%s does not contain efi eltorito\n", file->name);
2439 return 0;
2440 }
2441
2442 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2443 {
2444 char *pos;
2445 const char *fs = NULL;
2446 const char *cdprompt = NULL;
2447 grub_uint32_t i;
2448 grub_uint8_t chksum = 0;
2449 grub_disk_t disk;
2450
2451 disk = file->device->disk;
2452 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2453
2454 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2455 param->vtoy_disk_part_id = disk->partition->number + 1;
2456 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2457
2458 pos = grub_strstr(file->name, "/");
2459 if (!pos)
2460 {
2461 pos = file->name;
2462 }
2463
2464 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2465
2466 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2467
2468 param->vtoy_img_size = file->size;
2469
2470 param->vtoy_reserved[0] = g_ventoy_break_level;
2471 param->vtoy_reserved[1] = g_ventoy_debug_level;
2472
2473 param->vtoy_reserved[2] = g_ventoy_chain_type;
2474
2475 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2476 param->vtoy_reserved[4] = 0;
2477 if (g_ventoy_chain_type == 1) /* Windows */
2478 {
2479 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2480 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2481 {
2482 param->vtoy_reserved[4] = 1;
2483 }
2484 }
2485
2486 fs = ventoy_get_env("ventoy_fs_probe");
2487 if (fs && grub_strcmp(fs, "udf") == 0)
2488 {
2489 param->vtoy_reserved[3] = 1;
2490 }
2491
2492 /* calculate checksum */
2493 for (i = 0; i < sizeof(ventoy_os_param); i++)
2494 {
2495 chksum += *((grub_uint8_t *)param + i);
2496 }
2497 param->chksum = (grub_uint8_t)(0x100 - chksum);
2498
2499 return;
2500 }
2501
2502 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2503 {
2504 grub_uint32_t i = 0;
2505 grub_uint64_t total = 0;
2506 grub_uint64_t fileblk = 0;
2507 ventoy_img_chunk *chunk = NULL;
2508
2509 for (i = 0; i < chunklist->cur_chunk; i++)
2510 {
2511 chunk = chunklist->chunk + i;
2512
2513 if (chunk->disk_start_sector <= start)
2514 {
2515 debug("%u disk start invalid %lu\n", i, (ulong)start);
2516 return 1;
2517 }
2518
2519 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2520 }
2521
2522 fileblk = (file->size + 511) / 512;
2523
2524 if (total != fileblk)
2525 {
2526 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
2527 if ((file->size % 512) && (total + 1 == fileblk))
2528 {
2529 debug("maybe img file to be processed.\n");
2530 return 0;
2531 }
2532
2533 return 1;
2534 }
2535
2536 return 0;
2537 }
2538
2539 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2540 {
2541 int fs_type;
2542 int len;
2543 grub_uint32_t i = 0;
2544 grub_uint32_t sector = 0;
2545 grub_uint32_t count = 0;
2546 grub_off_t size = 0;
2547 grub_off_t read = 0;
2548
2549 fs_type = ventoy_get_fs_type(file->fs->name);
2550 if (fs_type == ventoy_fs_exfat)
2551 {
2552 grub_fat_get_file_chunk(start, file, chunklist);
2553 }
2554 else if (fs_type == ventoy_fs_ext)
2555 {
2556 grub_ext_get_file_chunk(start, file, chunklist);
2557 }
2558 else
2559 {
2560 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2561 file->read_hook_data = chunklist;
2562
2563 for (size = file->size; size > 0; size -= read)
2564 {
2565 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2566 grub_file_read(file, NULL, read);
2567 }
2568
2569 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2570 {
2571 chunklist->chunk[i].disk_start_sector += start;
2572 chunklist->chunk[i].disk_end_sector += start;
2573 }
2574
2575 if (ventoy_fs_udf == fs_type)
2576 {
2577 for (i = 0; i < chunklist->cur_chunk; i++)
2578 {
2579 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2580 chunklist->chunk[i].img_start_sector = sector;
2581 chunklist->chunk[i].img_end_sector = sector + count - 1;
2582 sector += count;
2583 }
2584 }
2585 }
2586
2587 len = (int)grub_strlen(file->name);
2588 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2589 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2590 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2591 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2592 {
2593 for (i = 0; i < chunklist->cur_chunk; i++)
2594 {
2595 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2596 if (count < 4)
2597 {
2598 count = 1;
2599 }
2600 else
2601 {
2602 count >>= 2;
2603 }
2604
2605 chunklist->chunk[i].img_start_sector = sector;
2606 chunklist->chunk[i].img_end_sector = sector + count - 1;
2607 sector += count;
2608 }
2609 }
2610
2611 return 0;
2612 }
2613
2614 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2615 {
2616 int rc;
2617 grub_file_t file;
2618 grub_disk_addr_t start;
2619
2620 (void)ctxt;
2621 (void)argc;
2622
2623 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2624 if (!file)
2625 {
2626 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2627 }
2628
2629 g_conf_replace_node = NULL;
2630 g_conf_replace_offset = 0;
2631
2632 if (g_img_chunk_list.chunk)
2633 {
2634 grub_free(g_img_chunk_list.chunk);
2635 }
2636
2637 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2638 {
2639 grub_file_close(file);
2640 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2641 }
2642
2643 /* get image chunk data */
2644 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2645 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2646 if (NULL == g_img_chunk_list.chunk)
2647 {
2648 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2649 }
2650
2651 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2652 g_img_chunk_list.cur_chunk = 0;
2653
2654 start = file->device->disk->partition->start;
2655
2656 ventoy_get_block_list(file, &g_img_chunk_list, start);
2657
2658 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2659 grub_file_close(file);
2660
2661 if (rc)
2662 {
2663 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2664 }
2665
2666 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2667 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2668 }
2669
2670 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2671 {
2672 grub_uint64_t offset = 0;
2673 grub_uint32_t align = 0;
2674 grub_file_t file = NULL;
2675 conf_replace *node = NULL;
2676
2677 (void)ctxt;
2678 (void)argc;
2679 (void)args;
2680
2681 debug("select conf replace argc:%d\n", argc);
2682
2683 if (argc < 2)
2684 {
2685 return 0;
2686 }
2687
2688 node = ventoy_plugin_find_conf_replace(args[1]);
2689 if (!node)
2690 {
2691 debug("Conf replace not found for %s\n", args[1]);
2692 goto end;
2693 }
2694
2695 debug("Find conf replace for %s\n", args[1]);
2696
2697 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2698 if (!file)
2699 {
2700 debug("<(loop)%s> NOT exist\n", node->orgconf);
2701 goto end;
2702 }
2703
2704 offset = grub_iso9660_get_last_file_dirent_pos(file);
2705 grub_file_close(file);
2706
2707 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2708 if (!file)
2709 {
2710 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2711 goto end;
2712 }
2713
2714 align = ((int)file->size + 2047) / 2048 * 2048;
2715
2716 if (align > vtoy_max_replace_file_size)
2717 {
2718 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2719 goto end;
2720 }
2721
2722 grub_file_read(file, g_conf_replace_new_buf, file->size);
2723 g_conf_replace_new_len = (int)file->size;
2724 g_conf_replace_new_len_align = align;
2725
2726 g_conf_replace_node = node;
2727 g_conf_replace_offset = offset + 2;
2728
2729 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2730
2731 end:
2732 if (file)
2733 {
2734 grub_file_close(file);
2735 }
2736 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2737 }
2738
2739 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2740 {
2741 int i = 0;
2742 int pos = 0;
2743 char *buf = NULL;
2744 char configfile[128];
2745 install_template *node = NULL;
2746
2747 (void)ctxt;
2748 (void)argc;
2749 (void)args;
2750
2751 debug("select auto installation argc:%d\n", argc);
2752
2753 if (argc < 1)
2754 {
2755 return 0;
2756 }
2757
2758 node = ventoy_plugin_find_install_template(args[0]);
2759 if (!node)
2760 {
2761 debug("Auto install template not found for %s\n", args[0]);
2762 return 0;
2763 }
2764
2765 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2766 {
2767 node->cursel = node->autosel - 1;
2768 debug("Auto install template auto select %d\n", node->autosel);
2769 return 0;
2770 }
2771
2772 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2773 if (!buf)
2774 {
2775 return 0;
2776 }
2777
2778 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2779 " echo %s\n}\n", "123");
2780
2781 for (i = 0; i < node->templatenum; i++)
2782 {
2783 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2784 " echo 123\n}\n",
2785 node->templatepath[i].path);
2786 }
2787
2788 g_ventoy_menu_esc = 1;
2789 g_ventoy_suppress_esc = 1;
2790
2791 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2792 grub_script_execute_sourcecode(configfile);
2793
2794 g_ventoy_menu_esc = 0;
2795 g_ventoy_suppress_esc = 0;
2796
2797 grub_free(buf);
2798
2799 node->cursel = g_ventoy_last_entry - 1;
2800
2801 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2802 }
2803
2804 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2805 {
2806 int i = 0;
2807 int pos = 0;
2808 char *buf = NULL;
2809 char configfile[128];
2810 persistence_config *node;
2811
2812 (void)ctxt;
2813 (void)argc;
2814 (void)args;
2815
2816 debug("select persistence argc:%d\n", argc);
2817
2818 if (argc < 1)
2819 {
2820 return 0;
2821 }
2822
2823 node = ventoy_plugin_find_persistent(args[0]);
2824 if (!node)
2825 {
2826 debug("Persistence image not found for %s\n", args[0]);
2827 return 0;
2828 }
2829
2830 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2831 {
2832 node->cursel = node->autosel - 1;
2833 debug("Persistence image auto select %d\n", node->autosel);
2834 return 0;
2835 }
2836
2837 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2838 if (!buf)
2839 {
2840 return 0;
2841 }
2842
2843 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2844 " echo %s\n}\n", "123");
2845
2846 for (i = 0; i < node->backendnum; i++)
2847 {
2848 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2849 " echo 123\n}\n",
2850 node->backendpath[i].path);
2851
2852 }
2853
2854 g_ventoy_menu_esc = 1;
2855 g_ventoy_suppress_esc = 1;
2856
2857 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2858 grub_script_execute_sourcecode(configfile);
2859
2860 g_ventoy_menu_esc = 0;
2861 g_ventoy_suppress_esc = 0;
2862
2863 grub_free(buf);
2864
2865 node->cursel = g_ventoy_last_entry - 1;
2866
2867 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2868 }
2869
2870 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2871 {
2872 grub_uint32_t i;
2873 ventoy_img_chunk *cur;
2874
2875 (void)ctxt;
2876 (void)argc;
2877 (void)args;
2878
2879 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2880 {
2881 cur = g_img_chunk_list.chunk + i;
2882 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2883 cur->img_start_sector, cur->img_end_sector,
2884 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2885 );
2886 }
2887
2888 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2889 }
2890
2891 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2892 {
2893 grub_uint32_t i;
2894 grub_file_t file;
2895 ventoy_img_chunk_list chunklist;
2896
2897 (void)ctxt;
2898 (void)argc;
2899
2900 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2901 if (!file)
2902 {
2903 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2904 }
2905
2906 /* get image chunk data */
2907 grub_memset(&chunklist, 0, sizeof(chunklist));
2908 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2909 if (NULL == chunklist.chunk)
2910 {
2911 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2912 }
2913
2914 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2915 chunklist.cur_chunk = 0;
2916
2917 ventoy_get_block_list(file, &chunklist, 0);
2918
2919 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2920 {
2921 grub_printf("########## UNSUPPORTED ###############\n");
2922 }
2923
2924 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2925
2926 for (i = 0; i < chunklist.cur_chunk; i++)
2927 {
2928 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2929 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2930 }
2931
2932 grub_printf("\n==================================\n");
2933
2934 for (i = 0; i < chunklist.cur_chunk; i++)
2935 {
2936 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2937 (ulonglong)chunklist.chunk[i].img_start_sector,
2938 (ulonglong)chunklist.chunk[i].img_end_sector,
2939 (ulonglong)chunklist.chunk[i].disk_start_sector,
2940 (ulonglong)chunklist.chunk[i].disk_end_sector
2941 );
2942 }
2943
2944 grub_free(chunklist.chunk);
2945 grub_file_close(file);
2946
2947 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2948 }
2949
2950 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2951 {
2952 int i;
2953 ventoy_grub_param_file_replace *replace = NULL;
2954
2955 (void)ctxt;
2956 (void)argc;
2957 (void)args;
2958
2959 if (argc >= 2)
2960 {
2961 replace = &(g_grub_param->file_replace);
2962 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2963
2964 replace->old_name_cnt = 0;
2965 for (i = 0; i < 4 && i + 1 < argc; i++)
2966 {
2967 replace->old_name_cnt++;
2968 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2969 }
2970
2971 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2972 }
2973
2974 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2975 }
2976
2977 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2978 {
2979 (void)ctxt;
2980 (void)argc;
2981 (void)args;
2982
2983 if (argc == 0)
2984 {
2985 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2986 grub_printf("%s", g_list_script_buf);
2987 }
2988 else
2989 {
2990 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2991 grub_printf("%s", g_tree_script_buf);
2992 }
2993
2994 return 0;
2995 }
2996
2997 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2998 {
2999 img_info *cur = g_ventoy_img_list;
3000
3001 (void)ctxt;
3002 (void)argc;
3003 (void)args;
3004
3005 while (cur)
3006 {
3007 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3008 grub_printf("name:<%s>\n\n", cur->name);
3009 cur = cur->next;
3010 }
3011
3012 return 0;
3013 }
3014
3015 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3016 {
3017 (void)ctxt;
3018 (void)argc;
3019 (void)args;
3020
3021 ventoy_plugin_dump_injection();
3022
3023 return 0;
3024 }
3025
3026 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3027 {
3028 (void)ctxt;
3029 (void)argc;
3030 (void)args;
3031
3032 ventoy_plugin_dump_auto_install();
3033
3034 return 0;
3035 }
3036
3037 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3038 {
3039 (void)ctxt;
3040 (void)argc;
3041 (void)args;
3042
3043 ventoy_plugin_dump_persistence();
3044
3045 return 0;
3046 }
3047
3048 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3049 {
3050 (void)ctxt;
3051 (void)argc;
3052 (void)args;
3053
3054 if (argc != 1)
3055 {
3056 return 1;
3057 }
3058
3059 if (args[0][0] == '0')
3060 {
3061 return g_ventoy_memdisk_mode ? 0 : 1;
3062 }
3063 else if (args[0][0] == '1')
3064 {
3065 return g_ventoy_iso_raw ? 0 : 1;
3066 }
3067 else if (args[0][0] == '2')
3068 {
3069 return g_ventoy_iso_uefi_drv ? 0 : 1;
3070 }
3071 else if (args[0][0] == '3')
3072 {
3073 return g_ventoy_grub2_mode ? 0 : 1;
3074 }
3075
3076 return 1;
3077 }
3078
3079 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3080 {
3081 static int configfile_mode = 0;
3082 char memfile[128] = {0};
3083
3084 (void)ctxt;
3085 (void)argc;
3086 (void)args;
3087
3088 /*
3089 * args[0]: 0:normal 1:configfile
3090 * args[1]: 0:list_buf 1:tree_buf
3091 */
3092
3093 if (argc != 2)
3094 {
3095 debug("Invalid argc %d\n", argc);
3096 return 0;
3097 }
3098
3099 if (args[0][0] == '0')
3100 {
3101 if (args[1][0] == '0')
3102 {
3103 grub_script_execute_sourcecode(g_list_script_buf);
3104 }
3105 else
3106 {
3107 grub_script_execute_sourcecode(g_tree_script_buf);
3108 }
3109 }
3110 else
3111 {
3112 if (configfile_mode)
3113 {
3114 debug("Now already in F3 mode %d\n", configfile_mode);
3115 return 0;
3116 }
3117
3118 if (args[1][0] == '0')
3119 {
3120 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3121 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3122 }
3123 else
3124 {
3125 g_ventoy_last_entry = -1;
3126 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3127 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3128 }
3129
3130 configfile_mode = 1;
3131 grub_script_execute_sourcecode(memfile);
3132 configfile_mode = 0;
3133 }
3134
3135 return 0;
3136 }
3137
3138 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3139 {
3140 grub_file_t file;
3141
3142 (void)ctxt;
3143
3144 if (argc != 1)
3145 {
3146 return 1;
3147 }
3148
3149 g_ventoy_case_insensitive = 1;
3150 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3151 g_ventoy_case_insensitive = 0;
3152
3153 grub_errno = 0;
3154
3155 if (file)
3156 {
3157 grub_file_close(file);
3158 return 0;
3159 }
3160 return 1;
3161 }
3162
3163 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3164 {
3165 int id = 0;
3166 int find = 0;
3167 grub_disk_t disk;
3168 const char *isopath = NULL;
3169 char hdname[32];
3170 ventoy_mbr_head mbr;
3171
3172 (void)ctxt;
3173 (void)argc;
3174
3175 if (argc != 1)
3176 {
3177 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3178 }
3179
3180 isopath = grub_env_get("vtoy_iso_part");
3181 if (!isopath)
3182 {
3183 debug("isopath is null %p\n", isopath);
3184 return 0;
3185 }
3186
3187 debug("isopath is %s\n", isopath);
3188
3189 for (id = 0; id < 30 && (find == 0); id++)
3190 {
3191 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3192 if (grub_strstr(isopath, hdname))
3193 {
3194 debug("skip %s ...\n", hdname);
3195 continue;
3196 }
3197
3198 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3199
3200 disk = grub_disk_open(hdname);
3201 if (!disk)
3202 {
3203 debug("%s not exist\n", hdname);
3204 break;
3205 }
3206
3207 grub_memset(&mbr, 0, sizeof(mbr));
3208 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3209 {
3210 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3211 {
3212 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3213 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3214 {
3215
3216 grub_env_set(args[0], hdname);
3217 find = 1;
3218 }
3219 }
3220 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3221 }
3222 else
3223 {
3224 debug("read %s failed\n", hdname);
3225 }
3226
3227 grub_disk_close(disk);
3228 }
3229
3230 return 0;
3231 }
3232
3233 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3234 {
3235 int len = 1024;
3236 grub_file_t file;
3237 char *buf = NULL;
3238
3239 (void)ctxt;
3240 (void)argc;
3241
3242 if (argc != 2)
3243 {
3244 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3245 }
3246
3247 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3248 if (!file)
3249 {
3250 debug("failed to open file %s\n", args[0]);
3251 return 0;
3252 }
3253
3254 buf = grub_malloc(len);
3255 if (!buf)
3256 {
3257 goto end;
3258 }
3259
3260 buf[len - 1] = 0;
3261 grub_file_read(file, buf, len - 1);
3262
3263 ventoy_get_line(buf);
3264 ventoy_set_env(args[1], buf);
3265
3266 end:
3267
3268 grub_check_free(buf);
3269 grub_file_close(file);
3270
3271 return 0;
3272 }
3273
3274 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3275 {
3276 (void)disk;
3277 (void)data;
3278
3279 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3280 "0 %llu linear /dev/ventoy %llu\n",
3281 (ulonglong)partition->len, (ulonglong)partition->start);
3282
3283 return 0;
3284 }
3285
3286 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3287 {
3288 char *device_name = NULL;
3289 grub_device_t dev = NULL;
3290 char buf[64];
3291
3292 (void)ctxt;
3293
3294 g_part_list_pos = 0;
3295 grub_env_unset("vtoy_img_part_file");
3296
3297 if (argc != 1)
3298 {
3299 return 1;
3300 }
3301
3302 device_name = grub_file_get_device_name(args[0]);
3303 if (!device_name)
3304 {
3305 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3306 goto end;
3307 }
3308
3309 dev = grub_device_open(device_name);
3310 if (!dev)
3311 {
3312 debug("grub_device_open failed, %s\n", device_name);
3313 goto end;
3314 }
3315
3316 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3317
3318 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3319 grub_env_set("vtoy_img_part_file", buf);
3320
3321 end:
3322
3323 check_free(device_name, grub_free);
3324 check_free(dev, grub_device_close);
3325
3326 return 0;
3327 }
3328
3329
3330 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3331 {
3332 int rc = 1;
3333 grub_file_t file;
3334 char *buf = NULL;
3335
3336 (void)ctxt;
3337 (void)argc;
3338
3339 if (argc != 2)
3340 {
3341 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3342 }
3343
3344 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3345 if (!file)
3346 {
3347 debug("failed to open file %s\n", args[0]);
3348 return 1;
3349 }
3350
3351 buf = grub_malloc(file->size + 1);
3352 if (!buf)
3353 {
3354 goto end;
3355 }
3356
3357 buf[file->size] = 0;
3358 grub_file_read(file, buf, file->size);
3359
3360 if (grub_strstr(buf, args[1]))
3361 {
3362 rc = 0;
3363 }
3364
3365 end:
3366
3367 grub_check_free(buf);
3368 grub_file_close(file);
3369
3370 return rc;
3371 }
3372
3373 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3374 {
3375 int len;
3376 grub_file_t file;
3377 char buf[64];
3378 grub_uint64_t size;
3379 ventoy_iso9660_vd pvd;
3380
3381 (void)ctxt;
3382 (void)argc;
3383
3384 if (argc != 4)
3385 {
3386 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3387 }
3388
3389 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3390 if (!file)
3391 {
3392 debug("failed to open file %s\n", args[0]);
3393 return 0;
3394 }
3395
3396 grub_file_seek(file, 16 * 2048);
3397 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3398 if (len != sizeof(pvd))
3399 {
3400 debug("failed to read pvd %d\n", len);
3401 goto end;
3402 }
3403
3404 grub_memset(buf, 0, sizeof(buf));
3405 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3406 ventoy_set_env(args[1], buf);
3407
3408 grub_memset(buf, 0, sizeof(buf));
3409 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3410 ventoy_set_env(args[2], buf);
3411
3412 size = pvd.space;
3413 size *= 2048;
3414 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3415 ventoy_set_env(args[3], buf);
3416
3417 end:
3418 grub_file_close(file);
3419
3420 return 0;
3421 }
3422
3423 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3424 {
3425 int len;
3426 grub_file_t file;
3427 char buf[64];
3428
3429 (void)ctxt;
3430 (void)argc;
3431
3432 if (argc != 2)
3433 {
3434 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3435 }
3436
3437 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3438 if (!file)
3439 {
3440 debug("failed to open file %s\n", args[0]);
3441 return 0;
3442 }
3443
3444 grub_memset(buf, 0, sizeof(buf));
3445 grub_file_seek(file, 16 * 2048 + 813);
3446 len = (int)grub_file_read(file, buf, 17);
3447 if (len != 17)
3448 {
3449 debug("failed to read create date %d\n", len);
3450 goto end;
3451 }
3452
3453 ventoy_set_env(args[1], buf);
3454
3455 end:
3456 grub_file_close(file);
3457
3458 return 0;
3459 }
3460
3461 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3462 {
3463 (void)ctxt;
3464 (void)argc;
3465 (void)args;
3466
3467 ventoy_env_hook_root(1);
3468
3469 return 0;
3470 }
3471
3472 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3473 {
3474 (void)ctxt;
3475 (void)argc;
3476 (void)args;
3477
3478 ventoy_env_hook_root(0);
3479
3480 return 0;
3481 }
3482
3483 #ifdef GRUB_MACHINE_EFI
3484 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3485 {
3486 int ret = 1;
3487 grub_uint8_t *var;
3488 grub_size_t size;
3489 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3490
3491 (void)ctxt;
3492 (void)argc;
3493 (void)args;
3494
3495 var = grub_efi_get_variable("SecureBoot", &global, &size);
3496 if (var && *var == 1)
3497 {
3498 return 0;
3499 }
3500
3501 return ret;
3502 }
3503 #else
3504 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3505 {
3506 (void)ctxt;
3507 (void)argc;
3508 (void)args;
3509 return 1;
3510 }
3511 #endif
3512
3513 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3514 {
3515 int i;
3516 int ret = 1;
3517 grub_file_t file;
3518 grub_uint64_t FileSectors = 0;
3519 ventoy_gpt_info *gpt = NULL;
3520 ventoy_part_table *pt = NULL;
3521 grub_uint8_t zeroguid[16] = {0};
3522
3523 (void)ctxt;
3524 (void)argc;
3525
3526 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3527 if (!file)
3528 {
3529 debug("failed to open file %s\n", args[0]);
3530 return 1;
3531 }
3532
3533 if (file->size % 512)
3534 {
3535 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3536 goto out;
3537 }
3538
3539 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3540 if (!gpt)
3541 {
3542 goto out;
3543 }
3544
3545 FileSectors = file->size / 512;
3546
3547 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3548 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3549 {
3550 debug("This is EFI partition table\n");
3551
3552 for (i = 0; i < 128; i++)
3553 {
3554 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3555 {
3556 if (FileSectors < gpt->PartTbl[i].LastLBA)
3557 {
3558 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3559 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3560 goto out;
3561 }
3562 }
3563 }
3564 }
3565 else
3566 {
3567 debug("This is MBR partition table\n");
3568
3569 for (i = 0; i < 4; i++)
3570 {
3571 pt = gpt->MBR.PartTbl + i;
3572 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3573 {
3574 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3575 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3576 (ulonglong)FileSectors);
3577 goto out;
3578 }
3579 }
3580 }
3581
3582 ret = 0;
3583
3584 out:
3585 grub_file_close(file);
3586 grub_check_free(gpt);
3587 grub_errno = GRUB_ERR_NONE;
3588 return ret;
3589 }
3590
3591 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3592 {
3593 int i;
3594 int ret;
3595
3596 (void)ctxt;
3597 (void)argc;
3598 (void)args;
3599
3600 for (i = 0; i < 500; i++)
3601 {
3602 ret = grub_getkey_noblock();
3603 if (ret == GRUB_TERM_NO_KEY)
3604 {
3605 break;
3606 }
3607 }
3608
3609 if (i >= 500)
3610 {
3611 grub_cls();
3612 grub_printf("\n\n Still have key input after clear.\n");
3613 grub_refresh();
3614 grub_sleep(5);
3615 }
3616
3617 return 0;
3618 }
3619
3620 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3621 {
3622 int i;
3623 int buflen;
3624 int datalen;
3625 int loclen;
3626 int img_chunk_num;
3627 int image_sector_size;
3628 char cmd[64];
3629 ventoy_chain_head *chain;
3630 ventoy_img_chunk *chunk;
3631 ventoy_os_param *osparam;
3632 ventoy_image_location *location;
3633 ventoy_image_disk_region *region;
3634 struct grub_acpi_table_header *acpi;
3635
3636 (void)ctxt;
3637
3638 if (argc != 2)
3639 {
3640 return 1;
3641 }
3642
3643 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3644
3645 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3646 if (!chain)
3647 {
3648 return 1;
3649 }
3650
3651 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3652
3653 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3654 {
3655 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3656 return 1;
3657 }
3658
3659 img_chunk_num = chain->img_chunk_num;
3660
3661 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3662 datalen = sizeof(ventoy_os_param) + loclen;
3663
3664 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3665 acpi = grub_zalloc(buflen);
3666 if (!acpi)
3667 {
3668 return 1;
3669 }
3670
3671 /* Step1: Fill acpi table header */
3672 grub_memcpy(acpi->signature, "VTOY", 4);
3673 acpi->length = buflen;
3674 acpi->revision = 1;
3675 grub_memcpy(acpi->oemid, "VENTOY", 6);
3676 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3677 acpi->oemrev = 1;
3678 acpi->creator_id[0] = 1;
3679 acpi->creator_rev = 1;
3680
3681 /* Step2: Fill data */
3682 osparam = (ventoy_os_param *)(acpi + 1);
3683 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3684 osparam->vtoy_img_location_addr = 0;
3685 osparam->vtoy_img_location_len = loclen;
3686 osparam->chksum = 0;
3687 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3688
3689 location = (ventoy_image_location *)(osparam + 1);
3690 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3691 location->image_sector_size = image_sector_size;
3692 location->disk_sector_size = chain->disk_sector_size;
3693 location->region_count = img_chunk_num;
3694
3695 region = location->regions;
3696 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3697 if (512 == image_sector_size)
3698 {
3699 for (i = 0; i < img_chunk_num; i++)
3700 {
3701 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3702 region->image_start_sector = chunk->img_start_sector * 4;
3703 region->disk_start_sector = chunk->disk_start_sector;
3704 region++;
3705 chunk++;
3706 }
3707 }
3708 else
3709 {
3710 for (i = 0; i < img_chunk_num; i++)
3711 {
3712 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3713 region->image_start_sector = chunk->img_start_sector;
3714 region->disk_start_sector = chunk->disk_start_sector;
3715 region++;
3716 chunk++;
3717 }
3718 }
3719
3720 /* Step3: Fill acpi checksum */
3721 acpi->checksum = 0;
3722 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3723
3724 /* load acpi table */
3725 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3726 grub_script_execute_sourcecode(cmd);
3727
3728 grub_free(acpi);
3729
3730 VENTOY_CMD_RETURN(0);
3731 }
3732
3733 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3734 {
3735 (void)ctxt;
3736 (void)argc;
3737 (void)args;
3738
3739 g_ventoy_last_entry_back = g_ventoy_last_entry;
3740 g_ventoy_last_entry = -1;
3741
3742 return 0;
3743 }
3744
3745 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3746 {
3747 (void)ctxt;
3748 (void)argc;
3749 (void)args;
3750
3751 g_ventoy_last_entry = g_ventoy_last_entry_back;
3752
3753 return 0;
3754 }
3755
3756 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3757 {
3758 grub_uint64_t sectors;
3759
3760 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3761 {
3762 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3763 }
3764 else
3765 {
3766 sectors = gpt->MBR.PartTbl[0].SectorCount;
3767 }
3768
3769 return sectors * 512;
3770 }
3771
3772 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3773 {
3774 const char *pos = filename + 1;
3775
3776 if (info->dir)
3777 {
3778 while (*pos)
3779 {
3780 if (*pos == '.')
3781 {
3782 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3783 {
3784 grub_strncpy((char *)data, filename, 128);
3785 return 1;
3786 }
3787 }
3788 pos++;
3789 }
3790 }
3791
3792 return 0;
3793 }
3794
3795 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3796 {
3797 int rc = 1;
3798 char *device_name = NULL;
3799 grub_device_t dev = NULL;
3800 grub_fs_t fs = NULL;
3801 char buf[128] = {0};
3802
3803 (void)ctxt;
3804
3805 if (argc != 3)
3806 {
3807 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3808 return 1;
3809 }
3810
3811 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3812
3813 device_name = grub_file_get_device_name(args[0]);
3814 if (!device_name)
3815 {
3816 debug("grub_file_get_device_name failed, %s\n", args[0]);
3817 goto end;
3818 }
3819
3820 dev = grub_device_open(device_name);
3821 if (!dev)
3822 {
3823 debug("grub_device_open failed, %s\n", device_name);
3824 goto end;
3825 }
3826
3827 fs = grub_fs_probe(dev);
3828 if (!fs)
3829 {
3830 debug("grub_fs_probe failed, %s\n", device_name);
3831 goto end;
3832 }
3833
3834 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3835
3836 if (buf[0])
3837 {
3838 ventoy_set_env(args[2], buf);
3839 }
3840
3841 rc = 0;
3842
3843 end:
3844
3845 check_free(device_name, grub_free);
3846 check_free(dev, grub_device_close);
3847
3848 return rc;
3849 }
3850
3851 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3852 {
3853 char name[64];
3854 int ret;
3855 grub_disk_t disk;
3856 grub_device_t dev;
3857
3858 (void)argc;
3859 (void)ctxt;
3860
3861 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3862 if (!g_ventoy_part_info)
3863 {
3864 return 1;
3865 }
3866
3867 disk = grub_disk_open(args[0]);
3868 if (!disk)
3869 {
3870 debug("Failed to open disk %s\n", args[0]);
3871 return 1;
3872 }
3873
3874 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3875
3876 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3877 grub_disk_close(disk);
3878
3879 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3880 dev = grub_device_open(name);
3881 if (dev)
3882 {
3883 /* make sure that we are running in a correct Ventoy device */
3884 ret = ventoy_check_device(dev);
3885 grub_device_close(dev);
3886
3887 if (ret)
3888 {
3889 grub_exit();
3890 }
3891 }
3892
3893 return 0;
3894 }
3895
3896 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
3897 {
3898 int ret = 1;
3899 const char *vcfg = NULL;
3900
3901 (void)argc;
3902 (void)ctxt;
3903
3904 vcfg = ventoy_plugin_get_custom_boot(args[0]);
3905 if (vcfg)
3906 {
3907 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
3908 grub_env_set(args[1], vcfg);
3909 ret = 0;
3910 }
3911 else
3912 {
3913 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
3914 }
3915
3916 grub_errno = 0;
3917 return ret;
3918 }
3919
3920
3921 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3922 {
3923 int id;
3924 grub_uint8_t zeroguid[16] = {0};
3925
3926 (void)argc;
3927 (void)ctxt;
3928
3929 id = (int)grub_strtoul(args[0], NULL, 10);
3930 grub_errno = 0;
3931
3932 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3933 {
3934 if (id >= 1 && id <= 128)
3935 {
3936 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3937 {
3938 return 0;
3939 }
3940 }
3941 }
3942 else
3943 {
3944 if (id >= 1 && id <= 4)
3945 {
3946 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3947 {
3948 return 0;
3949 }
3950 }
3951 }
3952
3953 return 1;
3954 }
3955
3956 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3957 {
3958 int rc = 1;
3959 char *device_name = NULL;
3960 grub_device_t dev = NULL;
3961 grub_fs_t fs = NULL;
3962 char *label = NULL;
3963
3964 (void)ctxt;
3965
3966 debug("get fs label for %s\n", args[0]);
3967
3968 if (argc != 2)
3969 {
3970 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3971 return 1;
3972 }
3973
3974 device_name = grub_file_get_device_name(args[0]);
3975 if (!device_name)
3976 {
3977 debug("grub_file_get_device_name failed, %s\n", args[0]);
3978 goto end;
3979 }
3980
3981 dev = grub_device_open(device_name);
3982 if (!dev)
3983 {
3984 debug("grub_device_open failed, %s\n", device_name);
3985 goto end;
3986 }
3987
3988 fs = grub_fs_probe(dev);
3989 if (NULL == fs || NULL == fs->fs_label)
3990 {
3991 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
3992 goto end;
3993 }
3994
3995 fs->fs_label(dev, &label);
3996 if (label)
3997 {
3998 debug("label=<%s>\n", label);
3999 ventoy_set_env(args[1], label);
4000 grub_free(label);
4001 }
4002
4003 rc = 0;
4004
4005 end:
4006
4007 check_free(device_name, grub_free);
4008 check_free(dev, grub_device_close);
4009
4010 return rc;
4011 }
4012
4013 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4014 {
4015 if (!info->dir)
4016 {
4017 grub_snprintf((char *)data, 256, "%s", filename);
4018 return 1;
4019 }
4020
4021 return 0;
4022 }
4023
4024
4025 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4026 {
4027 int rc = 1;
4028 char *device_name = NULL;
4029 grub_device_t dev = NULL;
4030 grub_fs_t fs = NULL;
4031 char name[256] ={0};
4032
4033 (void)ctxt;
4034
4035 if (argc != 3)
4036 {
4037 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
4038 return 1;
4039 }
4040
4041 device_name = grub_file_get_device_name(args[0]);
4042 if (!device_name)
4043 {
4044 debug("grub_file_get_device_name failed, %s\n", args[0]);
4045 goto end;
4046 }
4047
4048 dev = grub_device_open(device_name);
4049 if (!dev)
4050 {
4051 debug("grub_device_open failed, %s\n", device_name);
4052 goto end;
4053 }
4054
4055 fs = grub_fs_probe(dev);
4056 if (!fs)
4057 {
4058 debug("grub_fs_probe failed, %s\n", device_name);
4059 goto end;
4060 }
4061
4062 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
4063 if (name[0])
4064 {
4065 ventoy_set_env(args[2], name);
4066 }
4067
4068 rc = 0;
4069
4070 end:
4071
4072 check_free(device_name, grub_free);
4073 check_free(dev, grub_device_close);
4074
4075 return rc;
4076 }
4077
4078 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4079 {
4080 char c;
4081 char *pos = NULL;
4082 char *end = NULL;
4083
4084 (void)ctxt;
4085
4086 if (argc != 2)
4087 {
4088 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4089 return 1;
4090 }
4091
4092 for (pos = args[0]; *pos; pos++)
4093 {
4094 if (*pos == '.')
4095 {
4096 end = pos;
4097 }
4098 }
4099
4100 if (end)
4101 {
4102 c = *end;
4103 *end = 0;
4104 }
4105
4106 grub_env_set(args[1], args[0]);
4107
4108 if (end)
4109 {
4110 *end = c;
4111 }
4112
4113 return 0;
4114 }
4115
4116 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4117 {
4118 int i;
4119 int len;
4120 const char *buf;
4121
4122 (void)ctxt;
4123
4124 if (argc != 2)
4125 {
4126 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4127 return 1;
4128 }
4129
4130 buf = args[0];
4131 len = (int)grub_strlen(buf);
4132 for (i = len; i > 0; i--)
4133 {
4134 if (buf[i - 1] == '/')
4135 {
4136 grub_env_set(args[1], buf + i);
4137 return 0;
4138 }
4139 }
4140
4141 grub_env_set(args[1], buf);
4142
4143 return 0;
4144 }
4145
4146 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4147 {
4148 struct grub_video_mode_info info;
4149 char buf[32];
4150
4151 (void)ctxt;
4152 (void)argc;
4153 (void)args;
4154
4155 if (!g_video_mode_list)
4156 {
4157 ventoy_enum_video_mode();
4158 }
4159
4160 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4161 {
4162 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4163 }
4164 else
4165 {
4166 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4167 }
4168
4169 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4170
4171 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4172 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4173
4174 VENTOY_CMD_RETURN(0);
4175 }
4176
4177 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4178 {
4179 struct grub_video_mode_info info;
4180 char buf[32];
4181
4182 (void)ctxt;
4183 (void)argc;
4184 (void)args;
4185
4186 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4187 {
4188 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4189 }
4190 else
4191 {
4192 grub_snprintf(buf, sizeof(buf), "0x0x0");
4193 }
4194
4195 grub_env_set(args[0], buf);
4196
4197 VENTOY_CMD_RETURN(0);
4198 }
4199
4200 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4201 {
4202 int id;
4203 char buf[32];
4204
4205 (void)ctxt;
4206 (void)argc;
4207
4208 if (!g_video_mode_list)
4209 {
4210 return 0;
4211 }
4212
4213 id = (int)grub_strtoul(args[0], NULL, 10);
4214 if (id < g_video_mode_num)
4215 {
4216 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4217 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4218 }
4219
4220 grub_env_set(args[1], buf);
4221
4222 VENTOY_CMD_RETURN(0);
4223 }
4224
4225 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
4226 {
4227 grub_uint64_t size = 0;
4228 grub_file_t file;
4229 va_list ap;
4230 char fullpath[256] = {0};
4231
4232 va_start (ap, fmt);
4233 grub_vsnprintf(fullpath, 255, fmt, ap);
4234 va_end (ap);
4235
4236 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
4237 if (!file)
4238 {
4239 debug("grub_file_open failed <%s>\n", fullpath);
4240 grub_errno = 0;
4241 return 0;
4242 }
4243
4244 size = file->size;
4245 grub_file_close(file);
4246 return size;
4247 }
4248
4249 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
4250 {
4251 va_list ap;
4252 grub_file_t file;
4253 char fullpath[256] = {0};
4254
4255 va_start (ap, fmt);
4256 grub_vsnprintf(fullpath, 255, fmt, ap);
4257 va_end (ap);
4258
4259 file = grub_file_open(fullpath, type);
4260 if (!file)
4261 {
4262 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
4263 grub_errno = 0;
4264 }
4265
4266 return file;
4267 }
4268
4269 int ventoy_is_file_exist(const char *fmt, ...)
4270 {
4271 va_list ap;
4272 int len;
4273 char *pos = NULL;
4274 char buf[256] = {0};
4275
4276 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
4277 pos = buf + 6;
4278
4279 va_start (ap, fmt);
4280 len = grub_vsnprintf(pos, 255, fmt, ap);
4281 va_end (ap);
4282
4283 grub_strncpy(pos + len, "\" ]", 3);
4284
4285 debug("script exec %s\n", buf);
4286
4287 if (0 == grub_script_execute_sourcecode(buf))
4288 {
4289 return 1;
4290 }
4291
4292 return 0;
4293 }
4294
4295 int ventoy_is_dir_exist(const char *fmt, ...)
4296 {
4297 va_list ap;
4298 int len;
4299 char *pos = NULL;
4300 char buf[256] = {0};
4301
4302 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
4303 pos = buf + 6;
4304
4305 va_start (ap, fmt);
4306 len = grub_vsnprintf(pos, 255, fmt, ap);
4307 va_end (ap);
4308
4309 grub_strncpy(pos + len, "\" ]", 3);
4310
4311 debug("script exec %s\n", buf);
4312
4313 if (0 == grub_script_execute_sourcecode(buf))
4314 {
4315 return 1;
4316 }
4317
4318 return 0;
4319 }
4320
4321 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
4322 {
4323 mz_stream s;
4324 grub_uint8_t *outbuf;
4325 grub_uint8_t gzHdr[10] =
4326 {
4327 0x1F, 0x8B, /* magic */
4328 8, /* z method */
4329 0, /* flags */
4330 0,0,0,0, /* mtime */
4331 4, /* xfl */
4332 3, /* OS */
4333 };
4334
4335 grub_memset(&s, 0, sizeof(mz_stream));
4336
4337 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
4338
4339 outbuf = (grub_uint8_t *)mem_out;
4340
4341 mem_out_len -= sizeof(gzHdr) + 8;
4342 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
4343 outbuf += sizeof(gzHdr);
4344
4345 s.avail_in = mem_in_len;
4346 s.next_in = mem_in;
4347
4348 s.avail_out = mem_out_len;
4349 s.next_out = outbuf;
4350
4351 mz_deflate(&s, MZ_FINISH);
4352
4353 mz_deflateEnd(&s);
4354
4355 outbuf += s.total_out;
4356 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4357 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4358
4359 return s.total_out + sizeof(gzHdr) + 8;
4360 }
4361
4362 static int ventoy_env_init(void)
4363 {
4364 char buf[64];
4365
4366 grub_env_set("vtdebug_flag", "");
4367
4368 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4369 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4370 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4371 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4372
4373 ventoy_filt_register(0, ventoy_wrapper_open);
4374
4375 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4376 if (g_grub_param)
4377 {
4378 g_grub_param->grub_env_get = grub_env_get;
4379 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4380 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4381 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4382 grub_env_set("env_param", buf);
4383 grub_env_set("ventoy_env_param", buf);
4384
4385 grub_env_export("env_param");
4386 grub_env_export("ventoy_env_param");
4387 }
4388
4389 return 0;
4390 }
4391
4392 static cmd_para ventoy_cmds[] =
4393 {
4394 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4395 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4396 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4397 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4398 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4399 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4400 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4401 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4402 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4403 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4404 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4405 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4406 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4407 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4408 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
4409 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4410 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4411 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4412 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4413 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4414 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4415 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4416 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4417 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4418
4419 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4420 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4421 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4422 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4423 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4424 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4425 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4426
4427 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4428 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4429 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4430 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4431 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4432 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4433 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4434 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4435 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4436
4437
4438 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4439 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4440 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4441 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4442 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4443 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4444 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4445 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4446 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4447 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4448 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4449
4450 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4451 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4452 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4453 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4454 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4455 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4456
4457 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4458 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4459 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4460 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4461 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4462 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4463 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4464 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4465 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4466 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4467
4468 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4469 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4470 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4471 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4472 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4473 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4474 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4475 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4476
4477 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4478 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4479 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4480
4481
4482 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4483 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4484 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4485
4486 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4487 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4488 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4489
4490
4491 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4492 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4493 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4494 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4495 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
4496 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4497 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4498 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4499 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4500 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4501 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4502
4503 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4504 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4505 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4506 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4507 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
4508 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
4509
4510 };
4511
4512
4513
4514 GRUB_MOD_INIT(ventoy)
4515 {
4516 grub_uint32_t i;
4517 cmd_para *cur = NULL;
4518
4519 ventoy_env_init();
4520
4521 ventoy_arch_mode_init();
4522
4523 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4524 {
4525 cur = ventoy_cmds + i;
4526 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4527 cur->summary, cur->description, cur->parser);
4528 }
4529 }
4530
4531 GRUB_MOD_FINI(ventoy)
4532 {
4533 grub_uint32_t i;
4534
4535 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4536 {
4537 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4538 }
4539 }
4540