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