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