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