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