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