]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
update CI build script
[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
2270 grub_file_seek(file, sector * 2048);
2271 grub_file_read(file, buf, sizeof(buf));
2272
2273 if (buf[0] == 0x01 && buf[1] == 0xEF)
2274 {
2275 debug("%s efi eltorito in Validation Entry\n", file->name);
2276 return 1;
2277 }
2278
2279 if (buf[0] == 0x01 && buf[1] == 0x00)
2280 {
2281 x86count++;
2282 }
2283
2284 for (i = 64; i < (int)sizeof(buf); i += 32)
2285 {
2286 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2287 {
2288 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2289 return 1;
2290 }
2291
2292 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2293 {
2294 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2295 return 1;
2296 }
2297 }
2298
2299 debug("%s does not contain efi eltorito\n", file->name);
2300 return 0;
2301 }
2302
2303 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2304 {
2305 char *pos;
2306 const char *fs = NULL;
2307 const char *cdprompt = NULL;
2308 grub_uint32_t i;
2309 grub_uint8_t chksum = 0;
2310 grub_disk_t disk;
2311
2312 disk = file->device->disk;
2313 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2314
2315 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2316 param->vtoy_disk_part_id = disk->partition->number + 1;
2317 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2318
2319 pos = grub_strstr(file->name, "/");
2320 if (!pos)
2321 {
2322 pos = file->name;
2323 }
2324
2325 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2326
2327 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2328
2329 param->vtoy_img_size = file->size;
2330
2331 param->vtoy_reserved[0] = g_ventoy_break_level;
2332 param->vtoy_reserved[1] = g_ventoy_debug_level;
2333
2334 param->vtoy_reserved[2] = g_ventoy_chain_type;
2335
2336 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2337 param->vtoy_reserved[4] = 0;
2338 if (g_ventoy_chain_type == 1) /* Windows */
2339 {
2340 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2341 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2342 {
2343 param->vtoy_reserved[4] = 1;
2344 }
2345 }
2346
2347 fs = ventoy_get_env("ventoy_fs_probe");
2348 if (fs && grub_strcmp(fs, "udf") == 0)
2349 {
2350 param->vtoy_reserved[3] = 1;
2351 }
2352
2353 /* calculate checksum */
2354 for (i = 0; i < sizeof(ventoy_os_param); i++)
2355 {
2356 chksum += *((grub_uint8_t *)param + i);
2357 }
2358 param->chksum = (grub_uint8_t)(0x100 - chksum);
2359
2360 return;
2361 }
2362
2363 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2364 {
2365 grub_uint32_t i = 0;
2366 grub_uint64_t total = 0;
2367 ventoy_img_chunk *chunk = NULL;
2368
2369 for (i = 0; i < chunklist->cur_chunk; i++)
2370 {
2371 chunk = chunklist->chunk + i;
2372
2373 if (chunk->disk_start_sector <= start)
2374 {
2375 debug("%u disk start invalid %lu\n", i, (ulong)start);
2376 return 1;
2377 }
2378
2379 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2380 }
2381
2382 if (total != ((file->size + 511) / 512))
2383 {
2384 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2385 return 1;
2386 }
2387
2388 return 0;
2389 }
2390
2391 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2392 {
2393 int fs_type;
2394 int len;
2395 grub_uint32_t i = 0;
2396 grub_uint32_t sector = 0;
2397 grub_uint32_t count = 0;
2398 grub_off_t size = 0;
2399 grub_off_t read = 0;
2400
2401 fs_type = ventoy_get_fs_type(file->fs->name);
2402 if (fs_type == ventoy_fs_exfat)
2403 {
2404 grub_fat_get_file_chunk(start, file, chunklist);
2405 }
2406 else if (fs_type == ventoy_fs_ext)
2407 {
2408 grub_ext_get_file_chunk(start, file, chunklist);
2409 }
2410 else
2411 {
2412 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2413 file->read_hook_data = chunklist;
2414
2415 for (size = file->size; size > 0; size -= read)
2416 {
2417 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2418 grub_file_read(file, NULL, read);
2419 }
2420
2421 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2422 {
2423 chunklist->chunk[i].disk_start_sector += start;
2424 chunklist->chunk[i].disk_end_sector += start;
2425 }
2426
2427 if (ventoy_fs_udf == fs_type)
2428 {
2429 for (i = 0; i < chunklist->cur_chunk; i++)
2430 {
2431 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2432 chunklist->chunk[i].img_start_sector = sector;
2433 chunklist->chunk[i].img_end_sector = sector + count - 1;
2434 sector += count;
2435 }
2436 }
2437 }
2438
2439 len = (int)grub_strlen(file->name);
2440 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2441 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2442 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2443 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2444 {
2445 for (i = 0; i < chunklist->cur_chunk; i++)
2446 {
2447 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2448 if (count < 4)
2449 {
2450 count = 1;
2451 }
2452 else
2453 {
2454 count >>= 2;
2455 }
2456
2457 chunklist->chunk[i].img_start_sector = sector;
2458 chunklist->chunk[i].img_end_sector = sector + count - 1;
2459 sector += count;
2460 }
2461 }
2462
2463 return 0;
2464 }
2465
2466 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2467 {
2468 int rc;
2469 grub_file_t file;
2470 grub_disk_addr_t start;
2471
2472 (void)ctxt;
2473 (void)argc;
2474
2475 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2476 if (!file)
2477 {
2478 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2479 }
2480
2481 g_conf_replace_node = NULL;
2482 g_conf_replace_offset = 0;
2483
2484 if (g_img_chunk_list.chunk)
2485 {
2486 grub_free(g_img_chunk_list.chunk);
2487 }
2488
2489 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2490 {
2491 grub_file_close(file);
2492 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2493 }
2494
2495 /* get image chunk data */
2496 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2497 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2498 if (NULL == g_img_chunk_list.chunk)
2499 {
2500 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2501 }
2502
2503 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2504 g_img_chunk_list.cur_chunk = 0;
2505
2506 start = file->device->disk->partition->start;
2507
2508 ventoy_get_block_list(file, &g_img_chunk_list, start);
2509
2510 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2511 grub_file_close(file);
2512
2513 if (rc)
2514 {
2515 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2516 }
2517
2518 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2519 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2520 }
2521
2522 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2523 {
2524 grub_uint64_t offset = 0;
2525 grub_uint32_t align = 0;
2526 grub_file_t file = NULL;
2527 conf_replace *node = NULL;
2528
2529 (void)ctxt;
2530 (void)argc;
2531 (void)args;
2532
2533 debug("select conf replace argc:%d\n", argc);
2534
2535 if (argc < 2)
2536 {
2537 return 0;
2538 }
2539
2540 node = ventoy_plugin_find_conf_replace(args[1]);
2541 if (!node)
2542 {
2543 debug("Conf replace not found for %s\n", args[1]);
2544 goto end;
2545 }
2546
2547 debug("Find conf replace for %s\n", args[1]);
2548
2549 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2550 if (!file)
2551 {
2552 debug("<(loop)%s> NOT exist\n", node->orgconf);
2553 goto end;
2554 }
2555
2556 offset = grub_iso9660_get_last_file_dirent_pos(file);
2557 grub_file_close(file);
2558
2559 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2560 if (!file)
2561 {
2562 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2563 goto end;
2564 }
2565
2566 align = ((int)file->size + 2047) / 2048 * 2048;
2567
2568 if (align > vtoy_max_replace_file_size)
2569 {
2570 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2571 goto end;
2572 }
2573
2574 grub_file_read(file, g_conf_replace_new_buf, file->size);
2575 g_conf_replace_new_len = (int)file->size;
2576 g_conf_replace_new_len_align = align;
2577
2578 g_conf_replace_node = node;
2579 g_conf_replace_offset = offset + 2;
2580
2581 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2582
2583 end:
2584 if (file)
2585 {
2586 grub_file_close(file);
2587 }
2588 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2589 }
2590
2591 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2592 {
2593 int i = 0;
2594 int pos = 0;
2595 char *buf = NULL;
2596 char configfile[128];
2597 install_template *node = NULL;
2598
2599 (void)ctxt;
2600 (void)argc;
2601 (void)args;
2602
2603 debug("select auto installation argc:%d\n", argc);
2604
2605 if (argc < 1)
2606 {
2607 return 0;
2608 }
2609
2610 node = ventoy_plugin_find_install_template(args[0]);
2611 if (!node)
2612 {
2613 debug("Auto install template not found for %s\n", args[0]);
2614 return 0;
2615 }
2616
2617 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2618 {
2619 node->cursel = node->autosel - 1;
2620 debug("Auto install template auto select %d\n", node->autosel);
2621 return 0;
2622 }
2623
2624 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2625 if (!buf)
2626 {
2627 return 0;
2628 }
2629
2630 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2631 " echo %s\n}\n", "123");
2632
2633 for (i = 0; i < node->templatenum; i++)
2634 {
2635 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2636 " echo 123\n}\n",
2637 node->templatepath[i].path);
2638 }
2639
2640 g_ventoy_menu_esc = 1;
2641 g_ventoy_suppress_esc = 1;
2642
2643 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2644 grub_script_execute_sourcecode(configfile);
2645
2646 g_ventoy_menu_esc = 0;
2647 g_ventoy_suppress_esc = 0;
2648
2649 grub_free(buf);
2650
2651 node->cursel = g_ventoy_last_entry - 1;
2652
2653 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2654 }
2655
2656 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2657 {
2658 int i = 0;
2659 int pos = 0;
2660 char *buf = NULL;
2661 char configfile[128];
2662 persistence_config *node;
2663
2664 (void)ctxt;
2665 (void)argc;
2666 (void)args;
2667
2668 debug("select persistence argc:%d\n", argc);
2669
2670 if (argc < 1)
2671 {
2672 return 0;
2673 }
2674
2675 node = ventoy_plugin_find_persistent(args[0]);
2676 if (!node)
2677 {
2678 debug("Persistence image not found for %s\n", args[0]);
2679 return 0;
2680 }
2681
2682 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2683 {
2684 node->cursel = node->autosel - 1;
2685 debug("Persistence image auto select %d\n", node->autosel);
2686 return 0;
2687 }
2688
2689 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2690 if (!buf)
2691 {
2692 return 0;
2693 }
2694
2695 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2696 " echo %s\n}\n", "123");
2697
2698 for (i = 0; i < node->backendnum; i++)
2699 {
2700 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2701 " echo 123\n}\n",
2702 node->backendpath[i].path);
2703
2704 }
2705
2706 g_ventoy_menu_esc = 1;
2707 g_ventoy_suppress_esc = 1;
2708
2709 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2710 grub_script_execute_sourcecode(configfile);
2711
2712 g_ventoy_menu_esc = 0;
2713 g_ventoy_suppress_esc = 0;
2714
2715 grub_free(buf);
2716
2717 node->cursel = g_ventoy_last_entry - 1;
2718
2719 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2720 }
2721
2722 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2723 {
2724 grub_uint32_t i;
2725 ventoy_img_chunk *cur;
2726
2727 (void)ctxt;
2728 (void)argc;
2729 (void)args;
2730
2731 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2732 {
2733 cur = g_img_chunk_list.chunk + i;
2734 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2735 cur->img_start_sector, cur->img_end_sector,
2736 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2737 );
2738 }
2739
2740 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2741 }
2742
2743 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2744 {
2745 grub_uint32_t i;
2746 grub_file_t file;
2747 ventoy_img_chunk_list chunklist;
2748
2749 (void)ctxt;
2750 (void)argc;
2751
2752 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2753 if (!file)
2754 {
2755 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2756 }
2757
2758 /* get image chunk data */
2759 grub_memset(&chunklist, 0, sizeof(chunklist));
2760 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2761 if (NULL == chunklist.chunk)
2762 {
2763 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2764 }
2765
2766 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2767 chunklist.cur_chunk = 0;
2768
2769 ventoy_get_block_list(file, &chunklist, 0);
2770
2771 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2772 {
2773 grub_printf("########## UNSUPPORTED ###############\n");
2774 }
2775
2776 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2777
2778 for (i = 0; i < chunklist.cur_chunk; i++)
2779 {
2780 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2781 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2782 }
2783
2784 grub_printf("\n==================================\n");
2785
2786 for (i = 0; i < chunklist.cur_chunk; i++)
2787 {
2788 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2789 (ulonglong)chunklist.chunk[i].img_start_sector,
2790 (ulonglong)chunklist.chunk[i].img_end_sector,
2791 (ulonglong)chunklist.chunk[i].disk_start_sector,
2792 (ulonglong)chunklist.chunk[i].disk_end_sector
2793 );
2794 }
2795
2796 grub_free(chunklist.chunk);
2797 grub_file_close(file);
2798
2799 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2800 }
2801
2802 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2803 {
2804 int i;
2805 ventoy_grub_param_file_replace *replace = NULL;
2806
2807 (void)ctxt;
2808 (void)argc;
2809 (void)args;
2810
2811 if (argc >= 2)
2812 {
2813 replace = &(g_grub_param->file_replace);
2814 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2815
2816 replace->old_name_cnt = 0;
2817 for (i = 0; i < 4 && i + 1 < argc; i++)
2818 {
2819 replace->old_name_cnt++;
2820 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2821 }
2822
2823 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2824 }
2825
2826 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2827 }
2828
2829 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2830 {
2831 (void)ctxt;
2832 (void)argc;
2833 (void)args;
2834
2835 if (argc == 0)
2836 {
2837 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2838 grub_printf("%s", g_list_script_buf);
2839 }
2840 else
2841 {
2842 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2843 grub_printf("%s", g_tree_script_buf);
2844 }
2845
2846 return 0;
2847 }
2848
2849 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2850 {
2851 img_info *cur = g_ventoy_img_list;
2852
2853 (void)ctxt;
2854 (void)argc;
2855 (void)args;
2856
2857 while (cur)
2858 {
2859 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2860 grub_printf("name:<%s>\n\n", cur->name);
2861 cur = cur->next;
2862 }
2863
2864 return 0;
2865 }
2866
2867 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2868 {
2869 (void)ctxt;
2870 (void)argc;
2871 (void)args;
2872
2873 ventoy_plugin_dump_injection();
2874
2875 return 0;
2876 }
2877
2878 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2879 {
2880 (void)ctxt;
2881 (void)argc;
2882 (void)args;
2883
2884 ventoy_plugin_dump_auto_install();
2885
2886 return 0;
2887 }
2888
2889 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2890 {
2891 (void)ctxt;
2892 (void)argc;
2893 (void)args;
2894
2895 ventoy_plugin_dump_persistence();
2896
2897 return 0;
2898 }
2899
2900 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2901 {
2902 (void)ctxt;
2903 (void)argc;
2904 (void)args;
2905
2906 if (argc != 1)
2907 {
2908 return 1;
2909 }
2910
2911 if (args[0][0] == '0')
2912 {
2913 return g_ventoy_memdisk_mode ? 0 : 1;
2914 }
2915 else if (args[0][0] == '1')
2916 {
2917 return g_ventoy_iso_raw ? 0 : 1;
2918 }
2919 else if (args[0][0] == '2')
2920 {
2921 return g_ventoy_iso_uefi_drv ? 0 : 1;
2922 }
2923
2924 return 1;
2925 }
2926
2927 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2928 {
2929 static int configfile_mode = 0;
2930 char memfile[128] = {0};
2931
2932 (void)ctxt;
2933 (void)argc;
2934 (void)args;
2935
2936 /*
2937 * args[0]: 0:normal 1:configfile
2938 * args[1]: 0:list_buf 1:tree_buf
2939 */
2940
2941 if (argc != 2)
2942 {
2943 debug("Invalid argc %d\n", argc);
2944 return 0;
2945 }
2946
2947 if (args[0][0] == '0')
2948 {
2949 if (args[1][0] == '0')
2950 {
2951 grub_script_execute_sourcecode(g_list_script_buf);
2952 }
2953 else
2954 {
2955 grub_script_execute_sourcecode(g_tree_script_buf);
2956 }
2957 }
2958 else
2959 {
2960 if (configfile_mode)
2961 {
2962 debug("Now already in F3 mode %d\n", configfile_mode);
2963 return 0;
2964 }
2965
2966 if (args[1][0] == '0')
2967 {
2968 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2969 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2970 }
2971 else
2972 {
2973 g_ventoy_last_entry = -1;
2974 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2975 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2976 }
2977
2978 configfile_mode = 1;
2979 grub_script_execute_sourcecode(memfile);
2980 configfile_mode = 0;
2981 }
2982
2983 return 0;
2984 }
2985
2986 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2987 {
2988 grub_file_t file;
2989
2990 (void)ctxt;
2991
2992 if (argc != 1)
2993 {
2994 return 1;
2995 }
2996
2997 g_ventoy_case_insensitive = 1;
2998 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2999 g_ventoy_case_insensitive = 0;
3000
3001 grub_errno = 0;
3002
3003 if (file)
3004 {
3005 grub_file_close(file);
3006 return 0;
3007 }
3008 return 1;
3009 }
3010
3011 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3012 {
3013 int id = 0;
3014 int find = 0;
3015 grub_disk_t disk;
3016 const char *isopath = NULL;
3017 char hdname[32];
3018 ventoy_mbr_head mbr;
3019
3020 (void)ctxt;
3021 (void)argc;
3022
3023 if (argc != 1)
3024 {
3025 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3026 }
3027
3028 isopath = grub_env_get("vtoy_iso_part");
3029 if (!isopath)
3030 {
3031 debug("isopath is null %p\n", isopath);
3032 return 0;
3033 }
3034
3035 debug("isopath is %s\n", isopath);
3036
3037 for (id = 0; id < 30 && (find == 0); id++)
3038 {
3039 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3040 if (grub_strstr(isopath, hdname))
3041 {
3042 debug("skip %s ...\n", hdname);
3043 continue;
3044 }
3045
3046 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3047
3048 disk = grub_disk_open(hdname);
3049 if (!disk)
3050 {
3051 debug("%s not exist\n", hdname);
3052 break;
3053 }
3054
3055 grub_memset(&mbr, 0, sizeof(mbr));
3056 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3057 {
3058 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3059 {
3060 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3061 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3062 {
3063
3064 grub_env_set(args[0], hdname);
3065 find = 1;
3066 }
3067 }
3068 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3069 }
3070 else
3071 {
3072 debug("read %s failed\n", hdname);
3073 }
3074
3075 grub_disk_close(disk);
3076 }
3077
3078 return 0;
3079 }
3080
3081 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3082 {
3083 int len = 1024;
3084 grub_file_t file;
3085 char *buf = NULL;
3086
3087 (void)ctxt;
3088 (void)argc;
3089
3090 if (argc != 2)
3091 {
3092 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3093 }
3094
3095 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3096 if (!file)
3097 {
3098 debug("failed to open file %s\n", args[0]);
3099 return 0;
3100 }
3101
3102 buf = grub_malloc(len);
3103 if (!buf)
3104 {
3105 goto end;
3106 }
3107
3108 buf[len - 1] = 0;
3109 grub_file_read(file, buf, len - 1);
3110
3111 ventoy_get_line(buf);
3112 ventoy_set_env(args[1], buf);
3113
3114 end:
3115
3116 grub_check_free(buf);
3117 grub_file_close(file);
3118
3119 return 0;
3120 }
3121
3122 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3123 {
3124 (void)disk;
3125 (void)data;
3126
3127 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3128 "0 %llu linear /dev/ventoy %llu\n",
3129 (ulonglong)partition->len, (ulonglong)partition->start);
3130
3131 return 0;
3132 }
3133
3134 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3135 {
3136 char *device_name = NULL;
3137 grub_device_t dev = NULL;
3138 char buf[64];
3139
3140 (void)ctxt;
3141
3142 g_part_list_pos = 0;
3143 grub_env_unset("vtoy_img_part_file");
3144
3145 if (argc != 1)
3146 {
3147 return 1;
3148 }
3149
3150 device_name = grub_file_get_device_name(args[0]);
3151 if (!device_name)
3152 {
3153 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3154 goto end;
3155 }
3156
3157 dev = grub_device_open(device_name);
3158 if (!dev)
3159 {
3160 debug("grub_device_open failed, %s\n", device_name);
3161 goto end;
3162 }
3163
3164 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3165
3166 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3167 grub_env_set("vtoy_img_part_file", buf);
3168
3169 end:
3170
3171 check_free(device_name, grub_free);
3172 check_free(dev, grub_device_close);
3173
3174 return 0;
3175 }
3176
3177
3178 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3179 {
3180 int rc = 1;
3181 grub_file_t file;
3182 char *buf = NULL;
3183
3184 (void)ctxt;
3185 (void)argc;
3186
3187 if (argc != 2)
3188 {
3189 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3190 }
3191
3192 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3193 if (!file)
3194 {
3195 debug("failed to open file %s\n", args[0]);
3196 return 1;
3197 }
3198
3199 buf = grub_malloc(file->size + 1);
3200 if (!buf)
3201 {
3202 goto end;
3203 }
3204
3205 buf[file->size] = 0;
3206 grub_file_read(file, buf, file->size);
3207
3208 if (grub_strstr(buf, args[1]))
3209 {
3210 rc = 0;
3211 }
3212
3213 end:
3214
3215 grub_check_free(buf);
3216 grub_file_close(file);
3217
3218 return rc;
3219 }
3220
3221 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3222 {
3223 int len;
3224 grub_file_t file;
3225 char buf[64];
3226 ventoy_iso9660_vd pvd;
3227
3228 (void)ctxt;
3229 (void)argc;
3230
3231 if (argc != 3)
3232 {
3233 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid \n", cmd_raw_name);
3234 }
3235
3236 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3237 if (!file)
3238 {
3239 debug("failed to open file %s\n", args[0]);
3240 return 0;
3241 }
3242
3243 grub_file_seek(file, 16 * 2048);
3244 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3245 if (len != sizeof(pvd))
3246 {
3247 debug("failed to read pvd %d\n", len);
3248 goto end;
3249 }
3250
3251 grub_memset(buf, 0, sizeof(buf));
3252 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3253 ventoy_set_env(args[1], buf);
3254
3255 grub_memset(buf, 0, sizeof(buf));
3256 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3257 ventoy_set_env(args[2], buf);
3258
3259 end:
3260 grub_file_close(file);
3261
3262 return 0;
3263 }
3264
3265 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3266 {
3267 int len;
3268 grub_file_t file;
3269 char buf[64];
3270
3271 (void)ctxt;
3272 (void)argc;
3273
3274 if (argc != 2)
3275 {
3276 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3277 }
3278
3279 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3280 if (!file)
3281 {
3282 debug("failed to open file %s\n", args[0]);
3283 return 0;
3284 }
3285
3286 grub_memset(buf, 0, sizeof(buf));
3287 grub_file_seek(file, 16 * 2048 + 813);
3288 len = (int)grub_file_read(file, buf, 17);
3289 if (len != 17)
3290 {
3291 debug("failed to read create date %d\n", len);
3292 goto end;
3293 }
3294
3295 ventoy_set_env(args[1], buf);
3296
3297 end:
3298 grub_file_close(file);
3299
3300 return 0;
3301 }
3302
3303 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3304 {
3305 (void)ctxt;
3306 (void)argc;
3307 (void)args;
3308
3309 ventoy_env_hook_root(1);
3310
3311 return 0;
3312 }
3313
3314 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3315 {
3316 (void)ctxt;
3317 (void)argc;
3318 (void)args;
3319
3320 ventoy_env_hook_root(0);
3321
3322 return 0;
3323 }
3324
3325 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3326 {
3327 int i;
3328 int buflen;
3329 int datalen;
3330 int loclen;
3331 int img_chunk_num;
3332 int image_sector_size;
3333 char cmd[64];
3334 ventoy_chain_head *chain;
3335 ventoy_img_chunk *chunk;
3336 ventoy_os_param *osparam;
3337 ventoy_image_location *location;
3338 ventoy_image_disk_region *region;
3339 struct grub_acpi_table_header *acpi;
3340
3341 (void)ctxt;
3342
3343 if (argc != 2)
3344 {
3345 return 1;
3346 }
3347
3348 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3349
3350 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3351 if (!chain)
3352 {
3353 return 1;
3354 }
3355
3356 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3357
3358 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3359 {
3360 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3361 return 1;
3362 }
3363
3364 img_chunk_num = chain->img_chunk_num;
3365
3366 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3367 datalen = sizeof(ventoy_os_param) + loclen;
3368
3369 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3370 acpi = grub_zalloc(buflen);
3371 if (!acpi)
3372 {
3373 return 1;
3374 }
3375
3376 /* Step1: Fill acpi table header */
3377 grub_memcpy(acpi->signature, "VTOY", 4);
3378 acpi->length = buflen;
3379 acpi->revision = 1;
3380 grub_memcpy(acpi->oemid, "VENTOY", 6);
3381 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3382 acpi->oemrev = 1;
3383 acpi->creator_id[0] = 1;
3384 acpi->creator_rev = 1;
3385
3386 /* Step2: Fill data */
3387 osparam = (ventoy_os_param *)(acpi + 1);
3388 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3389 osparam->vtoy_img_location_addr = 0;
3390 osparam->vtoy_img_location_len = loclen;
3391 osparam->chksum = 0;
3392 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3393
3394 location = (ventoy_image_location *)(osparam + 1);
3395 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3396 location->image_sector_size = image_sector_size;
3397 location->disk_sector_size = chain->disk_sector_size;
3398 location->region_count = img_chunk_num;
3399
3400 region = location->regions;
3401 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3402 if (512 == image_sector_size)
3403 {
3404 for (i = 0; i < img_chunk_num; i++)
3405 {
3406 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3407 region->image_start_sector = chunk->img_start_sector * 4;
3408 region->disk_start_sector = chunk->disk_start_sector;
3409 region++;
3410 chunk++;
3411 }
3412 }
3413 else
3414 {
3415 for (i = 0; i < img_chunk_num; i++)
3416 {
3417 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3418 region->image_start_sector = chunk->img_start_sector;
3419 region->disk_start_sector = chunk->disk_start_sector;
3420 region++;
3421 chunk++;
3422 }
3423 }
3424
3425 /* Step3: Fill acpi checksum */
3426 acpi->checksum = 0;
3427 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3428
3429 /* load acpi table */
3430 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3431 grub_script_execute_sourcecode(cmd);
3432
3433 grub_free(acpi);
3434
3435 VENTOY_CMD_RETURN(0);
3436 }
3437
3438 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3439 {
3440 (void)ctxt;
3441 (void)argc;
3442 (void)args;
3443
3444 g_ventoy_last_entry_back = g_ventoy_last_entry;
3445 g_ventoy_last_entry = -1;
3446
3447 return 0;
3448 }
3449
3450 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3451 {
3452 (void)ctxt;
3453 (void)argc;
3454 (void)args;
3455
3456 g_ventoy_last_entry = g_ventoy_last_entry_back;
3457
3458 return 0;
3459 }
3460
3461 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3462 {
3463 grub_uint64_t sectors;
3464
3465 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3466 {
3467 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3468 }
3469 else
3470 {
3471 sectors = gpt->MBR.PartTbl[0].SectorCount;
3472 }
3473
3474 return sectors * 512;
3475 }
3476
3477 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3478 {
3479 const char *pos = filename + 1;
3480
3481 if (info->dir)
3482 {
3483 while (*pos)
3484 {
3485 if (*pos == '.')
3486 {
3487 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3488 {
3489 grub_strncpy((char *)data, filename, 128);
3490 return 1;
3491 }
3492 }
3493 pos++;
3494 }
3495 }
3496
3497 return 0;
3498 }
3499
3500 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3501 {
3502 int rc = 1;
3503 char *device_name = NULL;
3504 grub_device_t dev = NULL;
3505 grub_fs_t fs = NULL;
3506 char buf[128] = {0};
3507
3508 (void)ctxt;
3509
3510 if (argc != 3)
3511 {
3512 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3513 return 1;
3514 }
3515
3516 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3517
3518 device_name = grub_file_get_device_name(args[0]);
3519 if (!device_name)
3520 {
3521 debug("grub_file_get_device_name failed, %s\n", args[0]);
3522 goto end;
3523 }
3524
3525 dev = grub_device_open(device_name);
3526 if (!dev)
3527 {
3528 debug("grub_device_open failed, %s\n", device_name);
3529 goto end;
3530 }
3531
3532 fs = grub_fs_probe(dev);
3533 if (!fs)
3534 {
3535 debug("grub_fs_probe failed, %s\n", device_name);
3536 goto end;
3537 }
3538
3539 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3540
3541 if (buf[0])
3542 {
3543 ventoy_set_env(args[2], buf);
3544 }
3545
3546 rc = 0;
3547
3548 end:
3549
3550 check_free(device_name, grub_free);
3551 check_free(dev, grub_device_close);
3552
3553 return rc;
3554 }
3555
3556 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3557 {
3558 char name[64];
3559 int ret;
3560 grub_disk_t disk;
3561 grub_device_t dev;
3562
3563 (void)argc;
3564 (void)ctxt;
3565
3566 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3567 if (!g_ventoy_part_info)
3568 {
3569 return 1;
3570 }
3571
3572 disk = grub_disk_open(args[0]);
3573 if (!disk)
3574 {
3575 debug("Failed to open disk %s\n", args[0]);
3576 return 1;
3577 }
3578
3579 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3580
3581 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3582 grub_disk_close(disk);
3583
3584 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3585 dev = grub_device_open(name);
3586 if (dev)
3587 {
3588 /* make sure that we are running in a correct Ventoy device */
3589 ret = ventoy_check_device(dev);
3590 grub_device_close(dev);
3591
3592 if (ret)
3593 {
3594 grub_exit();
3595 }
3596 }
3597
3598 return 0;
3599 }
3600
3601 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3602 {
3603 int id;
3604 grub_uint8_t zeroguid[16] = {0};
3605
3606 (void)argc;
3607 (void)ctxt;
3608
3609 id = (int)grub_strtoul(args[0], NULL, 10);
3610 grub_errno = 0;
3611
3612 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3613 {
3614 if (id >= 1 && id <= 128)
3615 {
3616 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3617 {
3618 return 0;
3619 }
3620 }
3621 }
3622 else
3623 {
3624 if (id >= 1 && id <= 4)
3625 {
3626 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3627 {
3628 return 0;
3629 }
3630 }
3631 }
3632
3633 return 1;
3634 }
3635
3636 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3637 {
3638 int rc = 1;
3639 char *device_name = NULL;
3640 grub_device_t dev = NULL;
3641 grub_fs_t fs = NULL;
3642 char *label = NULL;
3643
3644 (void)ctxt;
3645
3646 if (argc != 2)
3647 {
3648 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3649 return 1;
3650 }
3651
3652 device_name = grub_file_get_device_name(args[0]);
3653 if (!device_name)
3654 {
3655 debug("grub_file_get_device_name failed, %s\n", args[0]);
3656 goto end;
3657 }
3658
3659 dev = grub_device_open(device_name);
3660 if (!dev)
3661 {
3662 debug("grub_device_open failed, %s\n", device_name);
3663 goto end;
3664 }
3665
3666 fs = grub_fs_probe(dev);
3667 if (!fs)
3668 {
3669 debug("grub_fs_probe failed, %s\n", device_name);
3670 goto end;
3671 }
3672
3673 fs->fs_label(dev, &label);
3674 if (label)
3675 {
3676 ventoy_set_env(args[1], label);
3677 grub_free(label);
3678 }
3679
3680 rc = 0;
3681
3682 end:
3683
3684 check_free(device_name, grub_free);
3685 check_free(dev, grub_device_close);
3686
3687 return rc;
3688 }
3689
3690 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3691 {
3692 if (!info->dir)
3693 {
3694 grub_snprintf((char *)data, 256, "%s", filename);
3695 return 1;
3696 }
3697
3698 return 0;
3699 }
3700
3701
3702 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3703 {
3704 int rc = 1;
3705 char *device_name = NULL;
3706 grub_device_t dev = NULL;
3707 grub_fs_t fs = NULL;
3708 char name[256] ={0};
3709
3710 (void)ctxt;
3711
3712 if (argc != 3)
3713 {
3714 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3715 return 1;
3716 }
3717
3718 device_name = grub_file_get_device_name(args[0]);
3719 if (!device_name)
3720 {
3721 debug("grub_file_get_device_name failed, %s\n", args[0]);
3722 goto end;
3723 }
3724
3725 dev = grub_device_open(device_name);
3726 if (!dev)
3727 {
3728 debug("grub_device_open failed, %s\n", device_name);
3729 goto end;
3730 }
3731
3732 fs = grub_fs_probe(dev);
3733 if (!fs)
3734 {
3735 debug("grub_fs_probe failed, %s\n", device_name);
3736 goto end;
3737 }
3738
3739 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3740 if (name[0])
3741 {
3742 ventoy_set_env(args[2], name);
3743 }
3744
3745 rc = 0;
3746
3747 end:
3748
3749 check_free(device_name, grub_free);
3750 check_free(dev, grub_device_close);
3751
3752 return rc;
3753 }
3754
3755 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3756 {
3757 char c;
3758 char *pos = NULL;
3759 char *end = NULL;
3760
3761 (void)ctxt;
3762
3763 if (argc != 2)
3764 {
3765 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3766 return 1;
3767 }
3768
3769 for (pos = args[0]; *pos; pos++)
3770 {
3771 if (*pos == '.')
3772 {
3773 end = pos;
3774 }
3775 }
3776
3777 if (end)
3778 {
3779 c = *end;
3780 *end = 0;
3781 }
3782
3783 grub_env_set(args[1], args[0]);
3784
3785 if (end)
3786 {
3787 *end = c;
3788 }
3789
3790 return 0;
3791 }
3792
3793 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3794 {
3795 struct grub_video_mode_info info;
3796 char buf[32];
3797
3798 (void)ctxt;
3799 (void)argc;
3800 (void)args;
3801
3802 if (!g_video_mode_list)
3803 {
3804 ventoy_enum_video_mode();
3805 }
3806
3807 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3808 {
3809 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3810 }
3811 else
3812 {
3813 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3814 }
3815
3816 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3817
3818 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3819 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3820
3821 VENTOY_CMD_RETURN(0);
3822 }
3823
3824 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3825 {
3826 struct grub_video_mode_info info;
3827 char buf[32];
3828
3829 (void)ctxt;
3830 (void)argc;
3831 (void)args;
3832
3833 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3834 {
3835 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
3836 }
3837 else
3838 {
3839 grub_snprintf(buf, sizeof(buf), "0x0x0");
3840 }
3841
3842 grub_env_set(args[0], buf);
3843
3844 VENTOY_CMD_RETURN(0);
3845 }
3846
3847 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3848 {
3849 int id;
3850 char buf[32];
3851
3852 (void)ctxt;
3853 (void)argc;
3854
3855 if (!g_video_mode_list)
3856 {
3857 return 0;
3858 }
3859
3860 id = (int)grub_strtoul(args[0], NULL, 10);
3861 if (id < g_video_mode_num)
3862 {
3863 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
3864 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
3865 }
3866
3867 grub_env_set(args[1], buf);
3868
3869 VENTOY_CMD_RETURN(0);
3870 }
3871
3872 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
3873 {
3874 grub_uint64_t size = 0;
3875 grub_file_t file;
3876 va_list ap;
3877 char fullpath[256] = {0};
3878
3879 va_start (ap, fmt);
3880 grub_vsnprintf(fullpath, 255, fmt, ap);
3881 va_end (ap);
3882
3883 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
3884 if (!file)
3885 {
3886 debug("grub_file_open failed <%s>\n", fullpath);
3887 grub_errno = 0;
3888 return 0;
3889 }
3890
3891 size = file->size;
3892 grub_file_close(file);
3893 return size;
3894 }
3895
3896 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
3897 {
3898 va_list ap;
3899 grub_file_t file;
3900 char fullpath[256] = {0};
3901
3902 va_start (ap, fmt);
3903 grub_vsnprintf(fullpath, 255, fmt, ap);
3904 va_end (ap);
3905
3906 file = grub_file_open(fullpath, type);
3907 if (!file)
3908 {
3909 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
3910 grub_errno = 0;
3911 }
3912
3913 return file;
3914 }
3915
3916 int ventoy_is_file_exist(const char *fmt, ...)
3917 {
3918 va_list ap;
3919 int len;
3920 char *pos = NULL;
3921 char buf[256] = {0};
3922
3923 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
3924 pos = buf + 6;
3925
3926 va_start (ap, fmt);
3927 len = grub_vsnprintf(pos, 255, fmt, ap);
3928 va_end (ap);
3929
3930 grub_strncpy(pos + len, "\" ]", 3);
3931
3932 debug("script exec %s\n", buf);
3933
3934 if (0 == grub_script_execute_sourcecode(buf))
3935 {
3936 return 1;
3937 }
3938
3939 return 0;
3940 }
3941
3942 int ventoy_is_dir_exist(const char *fmt, ...)
3943 {
3944 va_list ap;
3945 int len;
3946 char *pos = NULL;
3947 char buf[256] = {0};
3948
3949 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
3950 pos = buf + 6;
3951
3952 va_start (ap, fmt);
3953 len = grub_vsnprintf(pos, 255, fmt, ap);
3954 va_end (ap);
3955
3956 grub_strncpy(pos + len, "\" ]", 3);
3957
3958 debug("script exec %s\n", buf);
3959
3960 if (0 == grub_script_execute_sourcecode(buf))
3961 {
3962 return 1;
3963 }
3964
3965 return 0;
3966 }
3967
3968 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
3969 {
3970 mz_stream s;
3971 grub_uint8_t *outbuf;
3972 grub_uint8_t gzHdr[10] =
3973 {
3974 0x1F, 0x8B, /* magic */
3975 8, /* z method */
3976 0, /* flags */
3977 0,0,0,0, /* mtime */
3978 4, /* xfl */
3979 3, /* OS */
3980 };
3981
3982 grub_memset(&s, 0, sizeof(mz_stream));
3983
3984 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
3985
3986 outbuf = (grub_uint8_t *)mem_out;
3987
3988 mem_out_len -= sizeof(gzHdr) + 8;
3989 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
3990 outbuf += sizeof(gzHdr);
3991
3992 s.avail_in = mem_in_len;
3993 s.next_in = mem_in;
3994
3995 s.avail_out = mem_out_len;
3996 s.next_out = outbuf;
3997
3998 mz_deflate(&s, MZ_FINISH);
3999
4000 mz_deflateEnd(&s);
4001
4002 outbuf += s.total_out;
4003 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
4004 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
4005
4006 return s.total_out + sizeof(gzHdr) + 8;
4007 }
4008
4009 static int ventoy_env_init(void)
4010 {
4011 char buf[64];
4012
4013 grub_env_set("vtdebug_flag", "");
4014
4015 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4016 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4017 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4018 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4019
4020 ventoy_filt_register(0, ventoy_wrapper_open);
4021
4022 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4023 if (g_grub_param)
4024 {
4025 g_grub_param->grub_env_get = grub_env_get;
4026 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4027 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4028 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4029 grub_env_set("env_param", buf);
4030 grub_env_set("ventoy_env_param", buf);
4031 grub_env_export("ventoy_env_param");
4032 }
4033
4034 return 0;
4035 }
4036
4037 static cmd_para ventoy_cmds[] =
4038 {
4039 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4040 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4041 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4042 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4043 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4044 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4045 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4046 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4047 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4048 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4049 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4050 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4051 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4052 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4053 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4054 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4055 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4056 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4057 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4058 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4059
4060 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4061 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4062 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4063 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4064 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4065 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4066 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4067
4068 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4069 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4070 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4071 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4072 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4073 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4074 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4075 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4076
4077
4078 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4079 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4080 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4081 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4082 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4083 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4084 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4085 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4086 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4087 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4088 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4089
4090 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4091 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4092 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4093 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4094 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4095 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4096
4097 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4098 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4099 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4100 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4101 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4102 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4103 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4104 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4105 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4106 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4107
4108 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4109 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4110 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4111 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4112 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4113 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4114 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4115 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4116
4117 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4118 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4119 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4120
4121
4122 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4123 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4124 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4125
4126 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4127 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4128 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4129
4130
4131 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4132 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4133 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4134 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4135 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4136 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4137 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4138 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4139 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4140 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4141
4142 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4143 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4144 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4145
4146 };
4147
4148
4149
4150 GRUB_MOD_INIT(ventoy)
4151 {
4152 grub_uint32_t i;
4153 cmd_para *cur = NULL;
4154
4155 ventoy_env_init();
4156
4157 ventoy_arch_mode_init();
4158
4159 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4160 {
4161 cur = ventoy_cmds + i;
4162 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4163 cur->summary, cur->description, cur->parser);
4164 }
4165 }
4166
4167 GRUB_MOD_FINI(ventoy)
4168 {
4169 grub_uint32_t i;
4170
4171 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4172 {
4173 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4174 }
4175 }
4176