]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
add missing source
[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)
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)
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)
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 (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 }
1284
1285 img = grub_zalloc(sizeof(img_info));
1286 if (img)
1287 {
1288 img->type = type;
1289 img->plugin_list_index = index;
1290 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1291
1292 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1293
1294 img->size = info->size;
1295 if (0 == img->size)
1296 {
1297 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1298 }
1299
1300 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1301 {
1302 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1303 grub_free(img);
1304 return 0;
1305 }
1306
1307 if (g_ventoy_img_list)
1308 {
1309 tail = *(node->tail);
1310 img->prev = tail;
1311 tail->next = img;
1312 }
1313 else
1314 {
1315 g_ventoy_img_list = img;
1316 }
1317
1318 img->id = g_ventoy_img_count;
1319 img->parent = node;
1320 if (node && NULL == node->firstiso)
1321 {
1322 node->firstiso = img;
1323 }
1324
1325 node->isocnt++;
1326 tmp = node->parent;
1327 while (tmp)
1328 {
1329 tmp->isocnt++;
1330 tmp = tmp->parent;
1331 }
1332
1333 *((img_info **)(node->tail)) = img;
1334 g_ventoy_img_count++;
1335
1336 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1337 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1338 if (!img->class)
1339 {
1340 img->class = g_menu_class[type];
1341 }
1342 img->menu_prefix = g_menu_prefix[type];
1343
1344 if (img_type_iso == type)
1345 {
1346 if (ventoy_plugin_check_memdisk(img->path))
1347 {
1348 img->menu_prefix = "miso";
1349 }
1350 }
1351
1352 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1353 }
1354 }
1355
1356 return 0;
1357 }
1358
1359 static int ventoy_arch_mode_init(void)
1360 {
1361 #ifdef GRUB_MACHINE_EFI
1362 if (grub_strcmp(GRUB_TARGET_CPU, "i386") == 0)
1363 {
1364 g_ventoy_plat_data = VTOY_PLAT_I386_UEFI;
1365 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "ia32");
1366 }
1367 else if (grub_strcmp(GRUB_TARGET_CPU, "arm64") == 0)
1368 {
1369 g_ventoy_plat_data = VTOY_PLAT_ARM64_UEFI;
1370 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "aa64");
1371 }
1372 else
1373 {
1374 g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI;
1375 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi");
1376 }
1377 #else
1378 g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY;
1379 grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy");
1380 #endif
1381
1382 return 0;
1383 }
1384
1385 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1386 {
1387 int len = GRUB_UINT_MAX;
1388 const char *value = NULL;
1389 char name[32] = {0};
1390 char plat[32] = {0};
1391 char guidstr[32] = {0};
1392 ventoy_guid guid = VENTOY_GUID;
1393 const char *fmt1 = NULL;
1394 const char *fmt2 = NULL;
1395 const char *fmt3 = NULL;
1396 grub_uint32_t *puint = (grub_uint32_t *)name;
1397 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1398 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1399 const char fmtcode[]={
1400 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1401 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1402 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1403 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1404 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1405 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1406 };
1407
1408 grub_memset(name, 0, sizeof(name));
1409 puint[0] = grub_swap_bytes32(0x56454e54);
1410 puint[3] = grub_swap_bytes32(0x4f4e0000);
1411 puint[2] = grub_swap_bytes32(0x45525349);
1412 puint[1] = grub_swap_bytes32(0x4f595f56);
1413 value = ventoy_get_env(name);
1414
1415 grub_memset(name, 0, sizeof(name));
1416 puint[1] = grub_swap_bytes32(0x5f544f50);
1417 puint[0] = grub_swap_bytes32(0x56544c45);
1418 fmt1 = ventoy_get_env(name);
1419 if (!fmt1)
1420 {
1421 fmt1 = fmtdata;
1422 }
1423
1424 grub_memset(name, 0, sizeof(name));
1425 puint[1] = grub_swap_bytes32(0x5f4c4654);
1426 puint[0] = grub_swap_bytes32(0x56544c45);
1427 fmt2 = ventoy_get_env(name);
1428
1429 grub_memset(name, 0, sizeof(name));
1430 puint[1] = grub_swap_bytes32(0x5f434c52);
1431 puint[0] = grub_swap_bytes32(0x56544c45);
1432 fmt3 = ventoy_get_env(name);
1433
1434 grub_memcpy(guidstr, &guid, sizeof(guid));
1435
1436 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1437
1438 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1439 #pragma GCC diagnostic push
1440 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1441 len = grub_snprintf(buffer, buflen, fmtcode,
1442 fmt1 ? fmt1 : fmtdata,
1443 fmt2 ? fmt2 : fmtdata + 4,
1444 value ? value : "", plat, guidstr,
1445 fmt3 ? fmt3 : fmtdata + 6);
1446 #pragma GCC diagnostic pop
1447
1448 grub_memset(name, 0, sizeof(name));
1449 puint[0] = grub_swap_bytes32(0x76746f79);
1450 puint[2] = grub_swap_bytes32(0x656e7365);
1451 puint[1] = grub_swap_bytes32(0x5f6c6963);
1452 ventoy_set_env(name, guidstr);
1453
1454 return len;
1455 }
1456
1457 int ventoy_check_password(const vtoy_password *pwd, int retry)
1458 {
1459 int offset;
1460 char input[256];
1461 grub_uint8_t md5[16];
1462
1463 while (retry--)
1464 {
1465 grub_memset(input, 0, sizeof(input));
1466
1467 grub_printf("Enter password: ");
1468 grub_refresh();
1469
1470 if (pwd->type == VTOY_PASSWORD_TXT)
1471 {
1472 grub_password_get(input, 128);
1473 if (grub_strcmp(pwd->text, input) == 0)
1474 {
1475 return 0;
1476 }
1477 }
1478 else if (pwd->type == VTOY_PASSWORD_MD5)
1479 {
1480 grub_password_get(input, 128);
1481 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1482 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1483 {
1484 return 0;
1485 }
1486 }
1487 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1488 {
1489 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1490 grub_password_get(input + offset, 128);
1491
1492 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1493 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1494 {
1495 return 0;
1496 }
1497 }
1498
1499 grub_printf("Invalid password!\n\n");
1500 grub_refresh();
1501 }
1502
1503 return 1;
1504 }
1505
1506 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1507 {
1508 img_info *minimg = NULL;
1509 img_info *img = (img_info *)(node->firstiso);
1510
1511 while (img && (img_iterator_node *)(img->parent) == node)
1512 {
1513 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1514 {
1515 minimg = img;
1516 }
1517 img = img->next;
1518 }
1519
1520 if (minimg)
1521 {
1522 minimg->select = 1;
1523 }
1524
1525 return minimg;
1526 }
1527
1528 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1529 {
1530 img_iterator_node *Minchild = NULL;
1531 img_iterator_node *child = node->firstchild;
1532
1533 while (child && child->parent == node)
1534 {
1535 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1536 {
1537 Minchild = child;
1538 }
1539 child = child->next;
1540 }
1541
1542 if (Minchild)
1543 {
1544 Minchild->select = 1;
1545 }
1546
1547 return Minchild;
1548 }
1549
1550 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1551 {
1552 int offset = 1;
1553 img_info *img = NULL;
1554 const char *dir_class = NULL;
1555 const char *dir_alias = NULL;
1556 img_iterator_node *child = NULL;
1557
1558 if (node->isocnt == 0 || node->done == 1)
1559 {
1560 return 0;
1561 }
1562
1563 if (node->parent && node->parent->dirlen < node->dirlen)
1564 {
1565 offset = node->parent->dirlen;
1566 }
1567
1568 if (node == &g_img_iterator_head)
1569 {
1570 if (g_default_menu_mode == 0)
1571 {
1572 if (g_tree_view_menu_style == 0)
1573 {
1574 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1575 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1576 " echo 'return ...' \n"
1577 "}\n", "<--");
1578 }
1579 else
1580 {
1581 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1582 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1583 " echo '%s ...' \n"
1584 "}\n", "return");
1585 }
1586 }
1587 }
1588 else
1589 {
1590 node->dir[node->dirlen - 1] = 0;
1591 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1592 if (!dir_class)
1593 {
1594 dir_class = "vtoydir";
1595 }
1596
1597 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1598 if (dir_alias)
1599 {
1600 if (g_tree_view_menu_style == 0)
1601 {
1602 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1603 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1604 "DIR", dir_alias, dir_class, node->dir + offset);
1605 }
1606 else
1607 {
1608 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1609 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1610 dir_alias, dir_class, node->dir + offset);
1611 }
1612 }
1613 else
1614 {
1615 dir_alias = node->dir + offset;
1616
1617 if (g_tree_view_menu_style == 0)
1618 {
1619 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1620 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1621 "DIR", dir_alias, dir_class, node->dir + offset);
1622 }
1623 else
1624 {
1625 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1626 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1627 dir_alias, dir_class, node->dir + offset);
1628 }
1629 }
1630
1631 if (g_tree_view_menu_style == 0)
1632 {
1633 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1634 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1635 " echo 'return ...' \n"
1636 "}\n", "<--");
1637 }
1638 else
1639 {
1640 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1641 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1642 " echo '%s ...' \n"
1643 "}\n", "return");
1644 }
1645 }
1646
1647 while ((child = ventoy_get_min_child(node)) != NULL)
1648 {
1649 ventoy_dynamic_tree_menu(child);
1650 }
1651
1652 while ((img = ventoy_get_min_iso(node)) != NULL)
1653 {
1654 if (g_tree_view_menu_style == 0)
1655 {
1656 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1657 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1658 " %s_%s \n"
1659 "}\n",
1660 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1661 img->unsupport ? "[***********] " : "",
1662 img->alias ? img->alias : img->name, img->class, img->id,
1663 img->menu_prefix,
1664 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1665 }
1666 else
1667 {
1668 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1669 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1670 " %s_%s \n"
1671 "}\n",
1672 img->unsupport ? "[***********] " : "",
1673 img->alias ? img->alias : img->name, img->class, img->id,
1674 img->menu_prefix,
1675 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1676 }
1677 }
1678
1679 if (node != &g_img_iterator_head)
1680 {
1681 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1682 }
1683
1684 node->done = 1;
1685 return 0;
1686 }
1687
1688 int ventoy_check_device_result(int ret)
1689 {
1690 char buf[32];
1691
1692 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1693 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1694 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1695
1696 if (ret)
1697 {
1698 grub_printf(VTOY_WARNING"\n");
1699 grub_printf(VTOY_WARNING"\n");
1700 grub_printf(VTOY_WARNING"\n\n\n");
1701
1702 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1703 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1704
1705 grub_printf("\n\nWill exit after 10 seconds ...... ");
1706 grub_refresh();
1707 grub_sleep(10);
1708 }
1709
1710 return ret;
1711 }
1712
1713 int ventoy_check_device(grub_device_t dev)
1714 {
1715 int workaround = 0;
1716 grub_file_t file;
1717 grub_uint64_t offset;
1718 char devname[64];
1719 grub_fs_t fs;
1720 grub_device_t dev2;
1721 char *label = NULL;
1722 struct grub_partition *partition;
1723
1724 if (dev->disk == NULL || dev->disk->partition == NULL)
1725 {
1726 return ventoy_check_device_result(1 | 0x1000);
1727 }
1728
1729 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1730 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1731 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1732 {
1733 #ifndef GRUB_MACHINE_EFI
1734 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
1735 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
1736 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
1737 {
1738 return ventoy_check_device_result(2 | 0x1000);
1739 }
1740 else
1741 {
1742 workaround = 1;
1743 }
1744 #endif
1745 }
1746
1747 /* We must have partition 2 */
1748 if (workaround)
1749 {
1750 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1751 }
1752 else
1753 {
1754 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1755 }
1756 if (!file)
1757 {
1758 return ventoy_check_device_result(3 | 0x1000);
1759 }
1760
1761 if (NULL == grub_strstr(file->fs->name, "fat"))
1762 {
1763 grub_file_close(file);
1764 return ventoy_check_device_result(4 | 0x1000);
1765 }
1766
1767 partition = dev->disk->partition;
1768 if (partition->number != 0 || partition->start != 2048)
1769 {
1770 return ventoy_check_device_result(5);
1771 }
1772
1773 if (workaround)
1774 {
1775 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
1776 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
1777 PartTbl[1].SectorCount != 65536)
1778 {
1779 grub_file_close(file);
1780 return ventoy_check_device_result(6);
1781 }
1782 }
1783 else
1784 {
1785 offset = partition->start + partition->len;
1786 partition = file->device->disk->partition;
1787 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1788 {
1789 grub_file_close(file);
1790 return ventoy_check_device_result(7);
1791 }
1792 }
1793
1794 grub_file_close(file);
1795
1796 if (workaround == 0)
1797 {
1798 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1799 dev2 = grub_device_open(devname);
1800 if (!dev2)
1801 {
1802 return ventoy_check_device_result(8);
1803 }
1804
1805 fs = grub_fs_probe(dev2);
1806 if (!fs)
1807 {
1808 grub_device_close(dev2);
1809 return ventoy_check_device_result(9);
1810 }
1811
1812 fs->fs_label(dev2, &label);
1813 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1814 {
1815 grub_device_close(dev2);
1816 return ventoy_check_device_result(10);
1817 }
1818
1819 grub_device_close(dev2);
1820 }
1821
1822 return ventoy_check_device_result(0);
1823 }
1824
1825 static int ventoy_set_default_menu(void)
1826 {
1827 int img_len = 0;
1828 char *pos = NULL;
1829 char *end = NULL;
1830 char *def = NULL;
1831 const char *strdata = NULL;
1832 img_info *cur = NULL;
1833 img_info *default_node = NULL;
1834 const char *default_image = NULL;
1835
1836 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1837 if (default_image && default_image[0] == '/')
1838 {
1839 img_len = grub_strlen(default_image);
1840
1841 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1842 {
1843 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1844 {
1845 default_node = cur;
1846 break;
1847 }
1848 }
1849
1850 if (!default_node)
1851 {
1852 return 1;
1853 }
1854
1855 if (0 == g_default_menu_mode)
1856 {
1857 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1858 }
1859 else
1860 {
1861 def = grub_strdup(default_image);
1862 if (!def)
1863 {
1864 return 1;
1865 }
1866
1867 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1868
1869 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1870 if (strdata && strdata[0] == '/')
1871 {
1872 pos = def + grub_strlen(strdata);
1873 if (*pos == '/')
1874 {
1875 pos++;
1876 }
1877 }
1878 else
1879 {
1880 pos = def + 1;
1881 }
1882
1883 while ((end = grub_strchr(pos, '/')) != NULL)
1884 {
1885 *end = 0;
1886 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1887 pos = end + 1;
1888 }
1889
1890 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1891 grub_free(def);
1892 }
1893 }
1894
1895 return 0;
1896 }
1897
1898 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1899 {
1900 int len;
1901 grub_fs_t fs;
1902 grub_device_t dev = NULL;
1903 img_info *cur = NULL;
1904 img_info *tail = NULL;
1905 const char *strdata = NULL;
1906 char *device_name = NULL;
1907 char buf[32];
1908 img_iterator_node *node = NULL;
1909 img_iterator_node *tmp = NULL;
1910
1911 (void)ctxt;
1912
1913 if (argc != 2)
1914 {
1915 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1916 }
1917
1918 if (g_ventoy_img_list || g_ventoy_img_count)
1919 {
1920 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1921 }
1922
1923 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1924 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1925 {
1926 g_filt_dot_underscore_file = 1;
1927 }
1928
1929 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1930 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1931 {
1932 g_sort_case_sensitive = 1;
1933 }
1934
1935 device_name = grub_file_get_device_name(args[0]);
1936 if (!device_name)
1937 {
1938 goto fail;
1939 }
1940
1941 g_enum_dev = dev = grub_device_open(device_name);
1942 if (!dev)
1943 {
1944 goto fail;
1945 }
1946
1947 g_enum_fs = fs = grub_fs_probe(dev);
1948 if (!fs)
1949 {
1950 goto fail;
1951 }
1952
1953 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1954 {
1955 debug("unsupported fs:<%s>\n", fs->name);
1956 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1957 goto fail;
1958 }
1959
1960 ventoy_set_env("vtoy_iso_fs", fs->name);
1961
1962 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1963 if (strdata && strdata[0] == '1')
1964 {
1965 g_default_menu_mode = 1;
1966 }
1967
1968 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
1969
1970 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
1971
1972 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1973 if (strdata && strdata[0] == '/')
1974 {
1975 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
1976 if (g_img_iterator_head.dir[len - 1] != '/')
1977 {
1978 g_img_iterator_head.dir[len++] = '/';
1979 }
1980 g_img_iterator_head.dirlen = len;
1981 }
1982 else
1983 {
1984 g_img_iterator_head.dirlen = 1;
1985 grub_strcpy(g_img_iterator_head.dir, "/");
1986 }
1987
1988 g_img_iterator_head.tail = &tail;
1989
1990 for (node = &g_img_iterator_head; node; node = node->next)
1991 {
1992 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1993 }
1994
1995 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1996 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1997 {
1998 g_tree_view_menu_style = 1;
1999 }
2000
2001 ventoy_set_default_menu();
2002
2003 for (node = &g_img_iterator_head; node; node = node->next)
2004 {
2005 ventoy_dynamic_tree_menu(node);
2006 }
2007
2008 /* free node */
2009 node = g_img_iterator_head.next;
2010 while (node)
2011 {
2012 tmp = node->next;
2013 grub_free(node);
2014 node = tmp;
2015 }
2016
2017 /* sort image list by image name */
2018 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2019 {
2020 for (tail = cur->next; tail; tail = tail->next)
2021 {
2022 if (ventoy_cmp_img(cur, tail) > 0)
2023 {
2024 ventoy_swap_img(cur, tail);
2025 }
2026 }
2027 }
2028
2029 if (g_default_menu_mode == 1)
2030 {
2031 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2032 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2033 " echo 'return ...' \n"
2034 "}\n", "<--");
2035 }
2036
2037 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2038 {
2039 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2040 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2041 " %s_%s \n"
2042 "}\n",
2043 cur->unsupport ? "[***********] " : "",
2044 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
2045 cur->menu_prefix,
2046 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2047 }
2048
2049 g_tree_script_buf[g_tree_script_pos] = 0;
2050 g_list_script_buf[g_list_script_pos] = 0;
2051
2052 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2053 grub_env_set(args[1], buf);
2054
2055 fail:
2056
2057 check_free(device_name, grub_free);
2058 check_free(dev, grub_device_close);
2059
2060 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2061 }
2062
2063
2064 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2065 {
2066 img_info *next = NULL;
2067 img_info *cur = g_ventoy_img_list;
2068
2069 (void)ctxt;
2070 (void)argc;
2071 (void)args;
2072
2073 while (cur)
2074 {
2075 next = cur->next;
2076 grub_free(cur);
2077 cur = next;
2078 }
2079
2080 g_ventoy_img_list = NULL;
2081 g_ventoy_img_count = 0;
2082
2083 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2084 }
2085
2086 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2087 {
2088 long img_id = 0;
2089 img_info *cur = g_ventoy_img_list;
2090
2091 (void)ctxt;
2092
2093 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2094 {
2095 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2096 }
2097
2098 img_id = grub_strtol(args[0], NULL, 10);
2099 if (img_id >= g_ventoy_img_count)
2100 {
2101 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2102 }
2103
2104 debug("Find image %ld name \n", img_id);
2105
2106 while (cur && img_id > 0)
2107 {
2108 img_id--;
2109 cur = cur->next;
2110 }
2111
2112 if (!cur)
2113 {
2114 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2115 }
2116
2117 debug("image name is %s\n", cur->name);
2118
2119 grub_env_set(args[1], cur->name);
2120
2121 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2122 }
2123
2124 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2125 {
2126 int img_id = 0;
2127 char value[32];
2128 char *pos = NULL;
2129 const char *id = NULL;
2130 img_info *cur = g_ventoy_img_list;
2131
2132 (void)ctxt;
2133
2134 if (argc < 1 || argc > 2)
2135 {
2136 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2137 }
2138
2139 id = grub_env_get("chosen");
2140
2141 pos = grub_strstr(id, "VID_");
2142 if (pos)
2143 {
2144 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2145 }
2146 else
2147 {
2148 img_id = (int)grub_strtoul(id, NULL, 10);
2149 }
2150
2151 while (cur)
2152 {
2153 if (img_id == cur->id)
2154 {
2155 break;
2156 }
2157 cur = cur->next;
2158 }
2159
2160 if (!cur)
2161 {
2162 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2163 }
2164
2165 grub_env_set(args[0], cur->path);
2166
2167 if (argc > 1)
2168 {
2169 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2170 grub_env_set(args[1], value);
2171 }
2172
2173 g_svd_replace_offset = 0;
2174
2175 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2176 }
2177
2178 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2179 {
2180 grub_disk_t disk;
2181 char *device_name;
2182 char *pos;
2183 char *pos2;
2184
2185 device_name = grub_file_get_device_name(filename);
2186 if (!device_name)
2187 {
2188 return 1;
2189 }
2190
2191 pos = device_name;
2192 if (pos[0] == '(')
2193 {
2194 pos++;
2195 }
2196
2197 pos2 = grub_strstr(pos, ",");
2198 if (!pos2)
2199 {
2200 pos2 = grub_strstr(pos, ")");
2201 }
2202
2203 if (pos2)
2204 {
2205 *pos2 = 0;
2206 }
2207
2208 disk = grub_disk_open(pos);
2209 if (disk)
2210 {
2211 grub_disk_read(disk, 0, 0x180, 16, guid);
2212 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2213 grub_disk_close(disk);
2214 }
2215 else
2216 {
2217 return 1;
2218 }
2219
2220 grub_free(device_name);
2221 return 0;
2222 }
2223
2224 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2225 {
2226 eltorito_descriptor desc;
2227
2228 grub_memset(&desc, 0, sizeof(desc));
2229 grub_file_seek(file, 17 * 2048);
2230 grub_file_read(file, &desc, sizeof(desc));
2231
2232 if (desc.type != 0 || desc.version != 1)
2233 {
2234 return 0;
2235 }
2236
2237 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2238 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2239 {
2240 return 0;
2241 }
2242
2243 return desc.sector;
2244 }
2245
2246 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2247 {
2248 int i;
2249 int x86count = 0;
2250 grub_uint8_t buf[512];
2251
2252 grub_file_seek(file, sector * 2048);
2253 grub_file_read(file, buf, sizeof(buf));
2254
2255 if (buf[0] == 0x01 && buf[1] == 0xEF)
2256 {
2257 debug("%s efi eltorito in Validation Entry\n", file->name);
2258 return 1;
2259 }
2260
2261 if (buf[0] == 0x01 && buf[1] == 0x00)
2262 {
2263 x86count++;
2264 }
2265
2266 for (i = 64; i < (int)sizeof(buf); i += 32)
2267 {
2268 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2269 {
2270 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2271 return 1;
2272 }
2273
2274 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2275 {
2276 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2277 return 1;
2278 }
2279 }
2280
2281 debug("%s does not contain efi eltorito\n", file->name);
2282 return 0;
2283 }
2284
2285 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2286 {
2287 char *pos;
2288 const char *fs = NULL;
2289 const char *cdprompt = NULL;
2290 grub_uint32_t i;
2291 grub_uint8_t chksum = 0;
2292 grub_disk_t disk;
2293
2294 disk = file->device->disk;
2295 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2296
2297 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2298 param->vtoy_disk_part_id = disk->partition->number + 1;
2299 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2300
2301 pos = grub_strstr(file->name, "/");
2302 if (!pos)
2303 {
2304 pos = file->name;
2305 }
2306
2307 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2308
2309 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2310
2311 param->vtoy_img_size = file->size;
2312
2313 param->vtoy_reserved[0] = g_ventoy_break_level;
2314 param->vtoy_reserved[1] = g_ventoy_debug_level;
2315
2316 param->vtoy_reserved[2] = g_ventoy_chain_type;
2317
2318 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2319 param->vtoy_reserved[4] = 0;
2320 if (g_ventoy_chain_type == 1) /* Windows */
2321 {
2322 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2323 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2324 {
2325 param->vtoy_reserved[4] = 1;
2326 }
2327 }
2328
2329 fs = ventoy_get_env("ventoy_fs_probe");
2330 if (fs && grub_strcmp(fs, "udf") == 0)
2331 {
2332 param->vtoy_reserved[3] = 1;
2333 }
2334
2335 /* calculate checksum */
2336 for (i = 0; i < sizeof(ventoy_os_param); i++)
2337 {
2338 chksum += *((grub_uint8_t *)param + i);
2339 }
2340 param->chksum = (grub_uint8_t)(0x100 - chksum);
2341
2342 return;
2343 }
2344
2345 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2346 {
2347 grub_uint32_t i = 0;
2348 grub_uint64_t total = 0;
2349 ventoy_img_chunk *chunk = NULL;
2350
2351 for (i = 0; i < chunklist->cur_chunk; i++)
2352 {
2353 chunk = chunklist->chunk + i;
2354
2355 if (chunk->disk_start_sector <= start)
2356 {
2357 debug("%u disk start invalid %lu\n", i, (ulong)start);
2358 return 1;
2359 }
2360
2361 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2362 }
2363
2364 if (total != ((file->size + 511) / 512))
2365 {
2366 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2367 return 1;
2368 }
2369
2370 return 0;
2371 }
2372
2373 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2374 {
2375 int fs_type;
2376 int len;
2377 grub_uint32_t i = 0;
2378 grub_uint32_t sector = 0;
2379 grub_uint32_t count = 0;
2380 grub_off_t size = 0;
2381 grub_off_t read = 0;
2382
2383 fs_type = ventoy_get_fs_type(file->fs->name);
2384 if (fs_type == ventoy_fs_exfat)
2385 {
2386 grub_fat_get_file_chunk(start, file, chunklist);
2387 }
2388 else if (fs_type == ventoy_fs_ext)
2389 {
2390 grub_ext_get_file_chunk(start, file, chunklist);
2391 }
2392 else
2393 {
2394 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2395 file->read_hook_data = chunklist;
2396
2397 for (size = file->size; size > 0; size -= read)
2398 {
2399 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2400 grub_file_read(file, NULL, read);
2401 }
2402
2403 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2404 {
2405 chunklist->chunk[i].disk_start_sector += start;
2406 chunklist->chunk[i].disk_end_sector += start;
2407 }
2408
2409 if (ventoy_fs_udf == fs_type)
2410 {
2411 for (i = 0; i < chunklist->cur_chunk; i++)
2412 {
2413 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2414 chunklist->chunk[i].img_start_sector = sector;
2415 chunklist->chunk[i].img_end_sector = sector + count - 1;
2416 sector += count;
2417 }
2418 }
2419 }
2420
2421 len = (int)grub_strlen(file->name);
2422 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2423 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2424 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2425 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2426 {
2427 for (i = 0; i < chunklist->cur_chunk; i++)
2428 {
2429 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2430 if (count < 4)
2431 {
2432 count = 1;
2433 }
2434 else
2435 {
2436 count >>= 2;
2437 }
2438
2439 chunklist->chunk[i].img_start_sector = sector;
2440 chunklist->chunk[i].img_end_sector = sector + count - 1;
2441 sector += count;
2442 }
2443 }
2444
2445 return 0;
2446 }
2447
2448 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2449 {
2450 int rc;
2451 grub_file_t file;
2452 grub_disk_addr_t start;
2453
2454 (void)ctxt;
2455 (void)argc;
2456
2457 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2458 if (!file)
2459 {
2460 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2461 }
2462
2463 g_conf_replace_node = NULL;
2464 g_conf_replace_offset = 0;
2465
2466 if (g_img_chunk_list.chunk)
2467 {
2468 grub_free(g_img_chunk_list.chunk);
2469 }
2470
2471 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2472 {
2473 grub_file_close(file);
2474 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2475 }
2476
2477 /* get image chunk data */
2478 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2479 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2480 if (NULL == g_img_chunk_list.chunk)
2481 {
2482 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2483 }
2484
2485 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2486 g_img_chunk_list.cur_chunk = 0;
2487
2488 start = file->device->disk->partition->start;
2489
2490 ventoy_get_block_list(file, &g_img_chunk_list, start);
2491
2492 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2493 grub_file_close(file);
2494
2495 if (rc)
2496 {
2497 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2498 }
2499
2500 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2501 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2502 }
2503
2504 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2505 {
2506 grub_uint64_t offset = 0;
2507 grub_uint32_t align = 0;
2508 grub_file_t file = NULL;
2509 conf_replace *node = NULL;
2510
2511 (void)ctxt;
2512 (void)argc;
2513 (void)args;
2514
2515 debug("select conf replace argc:%d\n", argc);
2516
2517 if (argc < 2)
2518 {
2519 return 0;
2520 }
2521
2522 node = ventoy_plugin_find_conf_replace(args[1]);
2523 if (!node)
2524 {
2525 debug("Conf replace not found for %s\n", args[1]);
2526 goto end;
2527 }
2528
2529 debug("Find conf replace for %s\n", args[1]);
2530
2531 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2532 if (!file)
2533 {
2534 debug("<(loop)%s> NOT exist\n", node->orgconf);
2535 goto end;
2536 }
2537
2538 offset = grub_iso9660_get_last_file_dirent_pos(file);
2539 grub_file_close(file);
2540
2541 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2542 if (!file)
2543 {
2544 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2545 goto end;
2546 }
2547
2548 align = ((int)file->size + 2047) / 2048 * 2048;
2549
2550 if (align > vtoy_max_replace_file_size)
2551 {
2552 debug("New config file <%s%s> too big\n", args[0], node->newconf);
2553 goto end;
2554 }
2555
2556 grub_file_read(file, g_conf_replace_new_buf, file->size);
2557 g_conf_replace_new_len = (int)file->size;
2558 g_conf_replace_new_len_align = align;
2559
2560 g_conf_replace_node = node;
2561 g_conf_replace_offset = offset + 2;
2562
2563 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
2564
2565 end:
2566 if (file)
2567 {
2568 grub_file_close(file);
2569 }
2570 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2571 }
2572
2573 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2574 {
2575 int i = 0;
2576 int pos = 0;
2577 char *buf = NULL;
2578 char configfile[128];
2579 install_template *node = NULL;
2580
2581 (void)ctxt;
2582 (void)argc;
2583 (void)args;
2584
2585 debug("select auto installation argc:%d\n", argc);
2586
2587 if (argc < 1)
2588 {
2589 return 0;
2590 }
2591
2592 node = ventoy_plugin_find_install_template(args[0]);
2593 if (!node)
2594 {
2595 debug("Auto install template not found for %s\n", args[0]);
2596 return 0;
2597 }
2598
2599 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2600 {
2601 node->cursel = node->autosel - 1;
2602 debug("Auto install template auto select %d\n", node->autosel);
2603 return 0;
2604 }
2605
2606 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2607 if (!buf)
2608 {
2609 return 0;
2610 }
2611
2612 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2613 " echo %s\n}\n", "123");
2614
2615 for (i = 0; i < node->templatenum; i++)
2616 {
2617 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2618 " echo 123\n}\n",
2619 node->templatepath[i].path);
2620 }
2621
2622 g_ventoy_menu_esc = 1;
2623 g_ventoy_suppress_esc = 1;
2624
2625 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2626 grub_script_execute_sourcecode(configfile);
2627
2628 g_ventoy_menu_esc = 0;
2629 g_ventoy_suppress_esc = 0;
2630
2631 grub_free(buf);
2632
2633 node->cursel = g_ventoy_last_entry - 1;
2634
2635 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2636 }
2637
2638 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2639 {
2640 int i = 0;
2641 int pos = 0;
2642 char *buf = NULL;
2643 char configfile[128];
2644 persistence_config *node;
2645
2646 (void)ctxt;
2647 (void)argc;
2648 (void)args;
2649
2650 debug("select persistence argc:%d\n", argc);
2651
2652 if (argc < 1)
2653 {
2654 return 0;
2655 }
2656
2657 node = ventoy_plugin_find_persistent(args[0]);
2658 if (!node)
2659 {
2660 debug("Persistence image not found for %s\n", args[0]);
2661 return 0;
2662 }
2663
2664 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2665 {
2666 node->cursel = node->autosel - 1;
2667 debug("Persistence image auto select %d\n", node->autosel);
2668 return 0;
2669 }
2670
2671 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2672 if (!buf)
2673 {
2674 return 0;
2675 }
2676
2677 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2678 " echo %s\n}\n", "123");
2679
2680 for (i = 0; i < node->backendnum; i++)
2681 {
2682 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2683 " echo 123\n}\n",
2684 node->backendpath[i].path);
2685
2686 }
2687
2688 g_ventoy_menu_esc = 1;
2689 g_ventoy_suppress_esc = 1;
2690
2691 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2692 grub_script_execute_sourcecode(configfile);
2693
2694 g_ventoy_menu_esc = 0;
2695 g_ventoy_suppress_esc = 0;
2696
2697 grub_free(buf);
2698
2699 node->cursel = g_ventoy_last_entry - 1;
2700
2701 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2702 }
2703
2704 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2705 {
2706 grub_uint32_t i;
2707 ventoy_img_chunk *cur;
2708
2709 (void)ctxt;
2710 (void)argc;
2711 (void)args;
2712
2713 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2714 {
2715 cur = g_img_chunk_list.chunk + i;
2716 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2717 cur->img_start_sector, cur->img_end_sector,
2718 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2719 );
2720 }
2721
2722 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2723 }
2724
2725 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2726 {
2727 grub_uint32_t i;
2728 grub_file_t file;
2729 ventoy_img_chunk_list chunklist;
2730
2731 (void)ctxt;
2732 (void)argc;
2733
2734 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2735 if (!file)
2736 {
2737 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2738 }
2739
2740 /* get image chunk data */
2741 grub_memset(&chunklist, 0, sizeof(chunklist));
2742 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2743 if (NULL == chunklist.chunk)
2744 {
2745 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2746 }
2747
2748 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2749 chunklist.cur_chunk = 0;
2750
2751 ventoy_get_block_list(file, &chunklist, 0);
2752
2753 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2754 {
2755 grub_printf("########## UNSUPPORTED ###############\n");
2756 }
2757
2758 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2759
2760 for (i = 0; i < chunklist.cur_chunk; i++)
2761 {
2762 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2763 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2764 }
2765
2766 grub_printf("\n==================================\n");
2767
2768 for (i = 0; i < chunklist.cur_chunk; i++)
2769 {
2770 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2771 (ulonglong)chunklist.chunk[i].img_start_sector,
2772 (ulonglong)chunklist.chunk[i].img_end_sector,
2773 (ulonglong)chunklist.chunk[i].disk_start_sector,
2774 (ulonglong)chunklist.chunk[i].disk_end_sector
2775 );
2776 }
2777
2778 grub_free(chunklist.chunk);
2779 grub_file_close(file);
2780
2781 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2782 }
2783
2784 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2785 {
2786 int i;
2787 ventoy_grub_param_file_replace *replace = NULL;
2788
2789 (void)ctxt;
2790 (void)argc;
2791 (void)args;
2792
2793 if (argc >= 2)
2794 {
2795 replace = &(g_grub_param->file_replace);
2796 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2797
2798 replace->old_name_cnt = 0;
2799 for (i = 0; i < 4 && i + 1 < argc; i++)
2800 {
2801 replace->old_name_cnt++;
2802 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2803 }
2804
2805 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2806 }
2807
2808 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2809 }
2810
2811 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2812 {
2813 (void)ctxt;
2814 (void)argc;
2815 (void)args;
2816
2817 if (argc == 0)
2818 {
2819 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2820 grub_printf("%s", g_list_script_buf);
2821 }
2822 else
2823 {
2824 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2825 grub_printf("%s", g_tree_script_buf);
2826 }
2827
2828 return 0;
2829 }
2830
2831 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2832 {
2833 img_info *cur = g_ventoy_img_list;
2834
2835 (void)ctxt;
2836 (void)argc;
2837 (void)args;
2838
2839 while (cur)
2840 {
2841 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2842 grub_printf("name:<%s>\n\n", cur->name);
2843 cur = cur->next;
2844 }
2845
2846 return 0;
2847 }
2848
2849 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2850 {
2851 (void)ctxt;
2852 (void)argc;
2853 (void)args;
2854
2855 ventoy_plugin_dump_injection();
2856
2857 return 0;
2858 }
2859
2860 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2861 {
2862 (void)ctxt;
2863 (void)argc;
2864 (void)args;
2865
2866 ventoy_plugin_dump_auto_install();
2867
2868 return 0;
2869 }
2870
2871 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2872 {
2873 (void)ctxt;
2874 (void)argc;
2875 (void)args;
2876
2877 ventoy_plugin_dump_persistence();
2878
2879 return 0;
2880 }
2881
2882 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2883 {
2884 (void)ctxt;
2885 (void)argc;
2886 (void)args;
2887
2888 if (argc != 1)
2889 {
2890 return 1;
2891 }
2892
2893 if (args[0][0] == '0')
2894 {
2895 return g_ventoy_memdisk_mode ? 0 : 1;
2896 }
2897 else if (args[0][0] == '1')
2898 {
2899 return g_ventoy_iso_raw ? 0 : 1;
2900 }
2901 else if (args[0][0] == '2')
2902 {
2903 return g_ventoy_iso_uefi_drv ? 0 : 1;
2904 }
2905
2906 return 1;
2907 }
2908
2909 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2910 {
2911 static int configfile_mode = 0;
2912 char memfile[128] = {0};
2913
2914 (void)ctxt;
2915 (void)argc;
2916 (void)args;
2917
2918 /*
2919 * args[0]: 0:normal 1:configfile
2920 * args[1]: 0:list_buf 1:tree_buf
2921 */
2922
2923 if (argc != 2)
2924 {
2925 debug("Invalid argc %d\n", argc);
2926 return 0;
2927 }
2928
2929 if (args[0][0] == '0')
2930 {
2931 if (args[1][0] == '0')
2932 {
2933 grub_script_execute_sourcecode(g_list_script_buf);
2934 }
2935 else
2936 {
2937 grub_script_execute_sourcecode(g_tree_script_buf);
2938 }
2939 }
2940 else
2941 {
2942 if (configfile_mode)
2943 {
2944 debug("Now already in F3 mode %d\n", configfile_mode);
2945 return 0;
2946 }
2947
2948 if (args[1][0] == '0')
2949 {
2950 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2951 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2952 }
2953 else
2954 {
2955 g_ventoy_last_entry = -1;
2956 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2957 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2958 }
2959
2960 configfile_mode = 1;
2961 grub_script_execute_sourcecode(memfile);
2962 configfile_mode = 0;
2963 }
2964
2965 return 0;
2966 }
2967
2968 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2969 {
2970 grub_file_t file;
2971
2972 (void)ctxt;
2973
2974 if (argc != 1)
2975 {
2976 return 1;
2977 }
2978
2979 g_ventoy_case_insensitive = 1;
2980 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2981 g_ventoy_case_insensitive = 0;
2982
2983 grub_errno = 0;
2984
2985 if (file)
2986 {
2987 grub_file_close(file);
2988 return 0;
2989 }
2990 return 1;
2991 }
2992
2993 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
2994 {
2995 int id = 0;
2996 int find = 0;
2997 grub_disk_t disk;
2998 const char *isopath = NULL;
2999 char hdname[32];
3000 ventoy_mbr_head mbr;
3001
3002 (void)ctxt;
3003 (void)argc;
3004
3005 if (argc != 1)
3006 {
3007 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3008 }
3009
3010 isopath = grub_env_get("vtoy_iso_part");
3011 if (!isopath)
3012 {
3013 debug("isopath is null %p\n", isopath);
3014 return 0;
3015 }
3016
3017 debug("isopath is %s\n", isopath);
3018
3019 for (id = 0; id < 30 && (find == 0); id++)
3020 {
3021 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3022 if (grub_strstr(isopath, hdname))
3023 {
3024 debug("skip %s ...\n", hdname);
3025 continue;
3026 }
3027
3028 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3029
3030 disk = grub_disk_open(hdname);
3031 if (!disk)
3032 {
3033 debug("%s not exist\n", hdname);
3034 break;
3035 }
3036
3037 grub_memset(&mbr, 0, sizeof(mbr));
3038 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3039 {
3040 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3041 {
3042 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3043 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3044 {
3045
3046 grub_env_set(args[0], hdname);
3047 find = 1;
3048 }
3049 }
3050 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3051 }
3052 else
3053 {
3054 debug("read %s failed\n", hdname);
3055 }
3056
3057 grub_disk_close(disk);
3058 }
3059
3060 return 0;
3061 }
3062
3063 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3064 {
3065 int len = 1024;
3066 grub_file_t file;
3067 char *buf = NULL;
3068
3069 (void)ctxt;
3070 (void)argc;
3071
3072 if (argc != 2)
3073 {
3074 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3075 }
3076
3077 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3078 if (!file)
3079 {
3080 debug("failed to open file %s\n", args[0]);
3081 return 0;
3082 }
3083
3084 buf = grub_malloc(len);
3085 if (!buf)
3086 {
3087 goto end;
3088 }
3089
3090 buf[len - 1] = 0;
3091 grub_file_read(file, buf, len - 1);
3092
3093 ventoy_get_line(buf);
3094 ventoy_set_env(args[1], buf);
3095
3096 end:
3097
3098 grub_check_free(buf);
3099 grub_file_close(file);
3100
3101 return 0;
3102 }
3103
3104 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3105 {
3106 (void)disk;
3107 (void)data;
3108
3109 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3110 "0 %llu linear /dev/ventoy %llu\n",
3111 (ulonglong)partition->len, (ulonglong)partition->start);
3112
3113 return 0;
3114 }
3115
3116 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3117 {
3118 char *device_name = NULL;
3119 grub_device_t dev = NULL;
3120 char buf[64];
3121
3122 (void)ctxt;
3123
3124 g_part_list_pos = 0;
3125 grub_env_unset("vtoy_img_part_file");
3126
3127 if (argc != 1)
3128 {
3129 return 1;
3130 }
3131
3132 device_name = grub_file_get_device_name(args[0]);
3133 if (!device_name)
3134 {
3135 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3136 goto end;
3137 }
3138
3139 dev = grub_device_open(device_name);
3140 if (!dev)
3141 {
3142 debug("grub_device_open failed, %s\n", device_name);
3143 goto end;
3144 }
3145
3146 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3147
3148 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3149 grub_env_set("vtoy_img_part_file", buf);
3150
3151 end:
3152
3153 check_free(device_name, grub_free);
3154 check_free(dev, grub_device_close);
3155
3156 return 0;
3157 }
3158
3159
3160 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3161 {
3162 int rc = 1;
3163 grub_file_t file;
3164 char *buf = NULL;
3165
3166 (void)ctxt;
3167 (void)argc;
3168
3169 if (argc != 2)
3170 {
3171 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3172 }
3173
3174 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3175 if (!file)
3176 {
3177 debug("failed to open file %s\n", args[0]);
3178 return 1;
3179 }
3180
3181 buf = grub_malloc(file->size + 1);
3182 if (!buf)
3183 {
3184 goto end;
3185 }
3186
3187 buf[file->size] = 0;
3188 grub_file_read(file, buf, file->size);
3189
3190 if (grub_strstr(buf, args[1]))
3191 {
3192 rc = 0;
3193 }
3194
3195 end:
3196
3197 grub_check_free(buf);
3198 grub_file_close(file);
3199
3200 return rc;
3201 }
3202
3203 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3204 {
3205 int len;
3206 grub_file_t file;
3207 char buf[64];
3208 ventoy_iso9660_vd pvd;
3209
3210 (void)ctxt;
3211 (void)argc;
3212
3213 if (argc != 3)
3214 {
3215 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid \n", cmd_raw_name);
3216 }
3217
3218 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3219 if (!file)
3220 {
3221 debug("failed to open file %s\n", args[0]);
3222 return 0;
3223 }
3224
3225 grub_file_seek(file, 16 * 2048);
3226 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3227 if (len != sizeof(pvd))
3228 {
3229 debug("failed to read pvd %d\n", len);
3230 goto end;
3231 }
3232
3233 grub_memset(buf, 0, sizeof(buf));
3234 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3235 ventoy_set_env(args[1], buf);
3236
3237 grub_memset(buf, 0, sizeof(buf));
3238 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3239 ventoy_set_env(args[2], buf);
3240
3241 end:
3242 grub_file_close(file);
3243
3244 return 0;
3245 }
3246
3247 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3248 {
3249 int len;
3250 grub_file_t file;
3251 char buf[64];
3252
3253 (void)ctxt;
3254 (void)argc;
3255
3256 if (argc != 2)
3257 {
3258 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3259 }
3260
3261 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3262 if (!file)
3263 {
3264 debug("failed to open file %s\n", args[0]);
3265 return 0;
3266 }
3267
3268 grub_memset(buf, 0, sizeof(buf));
3269 grub_file_seek(file, 16 * 2048 + 813);
3270 len = (int)grub_file_read(file, buf, 17);
3271 if (len != 17)
3272 {
3273 debug("failed to read create date %d\n", len);
3274 goto end;
3275 }
3276
3277 ventoy_set_env(args[1], buf);
3278
3279 end:
3280 grub_file_close(file);
3281
3282 return 0;
3283 }
3284
3285 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3286 {
3287 (void)ctxt;
3288 (void)argc;
3289 (void)args;
3290
3291 ventoy_env_hook_root(1);
3292
3293 return 0;
3294 }
3295
3296 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3297 {
3298 (void)ctxt;
3299 (void)argc;
3300 (void)args;
3301
3302 ventoy_env_hook_root(0);
3303
3304 return 0;
3305 }
3306
3307 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3308 {
3309 int i;
3310 int buflen;
3311 int datalen;
3312 int loclen;
3313 int img_chunk_num;
3314 int image_sector_size;
3315 char cmd[64];
3316 ventoy_chain_head *chain;
3317 ventoy_img_chunk *chunk;
3318 ventoy_os_param *osparam;
3319 ventoy_image_location *location;
3320 ventoy_image_disk_region *region;
3321 struct grub_acpi_table_header *acpi;
3322
3323 (void)ctxt;
3324
3325 if (argc != 2)
3326 {
3327 return 1;
3328 }
3329
3330 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3331
3332 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3333 if (!chain)
3334 {
3335 return 1;
3336 }
3337
3338 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3339
3340 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3341 {
3342 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3343 return 1;
3344 }
3345
3346 img_chunk_num = chain->img_chunk_num;
3347
3348 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3349 datalen = sizeof(ventoy_os_param) + loclen;
3350
3351 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3352 acpi = grub_zalloc(buflen);
3353 if (!acpi)
3354 {
3355 return 1;
3356 }
3357
3358 /* Step1: Fill acpi table header */
3359 grub_memcpy(acpi->signature, "VTOY", 4);
3360 acpi->length = buflen;
3361 acpi->revision = 1;
3362 grub_memcpy(acpi->oemid, "VENTOY", 6);
3363 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3364 acpi->oemrev = 1;
3365 acpi->creator_id[0] = 1;
3366 acpi->creator_rev = 1;
3367
3368 /* Step2: Fill data */
3369 osparam = (ventoy_os_param *)(acpi + 1);
3370 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3371 osparam->vtoy_img_location_addr = 0;
3372 osparam->vtoy_img_location_len = loclen;
3373 osparam->chksum = 0;
3374 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3375
3376 location = (ventoy_image_location *)(osparam + 1);
3377 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3378 location->image_sector_size = image_sector_size;
3379 location->disk_sector_size = chain->disk_sector_size;
3380 location->region_count = img_chunk_num;
3381
3382 region = location->regions;
3383 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3384 if (512 == image_sector_size)
3385 {
3386 for (i = 0; i < img_chunk_num; i++)
3387 {
3388 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3389 region->image_start_sector = chunk->img_start_sector * 4;
3390 region->disk_start_sector = chunk->disk_start_sector;
3391 region++;
3392 chunk++;
3393 }
3394 }
3395 else
3396 {
3397 for (i = 0; i < img_chunk_num; i++)
3398 {
3399 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3400 region->image_start_sector = chunk->img_start_sector;
3401 region->disk_start_sector = chunk->disk_start_sector;
3402 region++;
3403 chunk++;
3404 }
3405 }
3406
3407 /* Step3: Fill acpi checksum */
3408 acpi->checksum = 0;
3409 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3410
3411 /* load acpi table */
3412 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3413 grub_script_execute_sourcecode(cmd);
3414
3415 grub_free(acpi);
3416
3417 VENTOY_CMD_RETURN(0);
3418 }
3419
3420 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3421 {
3422 (void)ctxt;
3423 (void)argc;
3424 (void)args;
3425
3426 g_ventoy_last_entry_back = g_ventoy_last_entry;
3427 g_ventoy_last_entry = -1;
3428
3429 return 0;
3430 }
3431
3432 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3433 {
3434 (void)ctxt;
3435 (void)argc;
3436 (void)args;
3437
3438 g_ventoy_last_entry = g_ventoy_last_entry_back;
3439
3440 return 0;
3441 }
3442
3443 grub_uint64_t ventoy_get_part1_size(ventoy_gpt_info *gpt)
3444 {
3445 grub_uint64_t sectors;
3446
3447 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3448 {
3449 sectors = gpt->PartTbl[0].LastLBA + 1 - gpt->PartTbl[0].StartLBA;
3450 }
3451 else
3452 {
3453 sectors = gpt->MBR.PartTbl[0].SectorCount;
3454 }
3455
3456 return sectors * 512;
3457 }
3458
3459 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3460 {
3461 const char *pos = filename + 1;
3462
3463 if (info->dir)
3464 {
3465 while (*pos)
3466 {
3467 if (*pos == '.')
3468 {
3469 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3470 {
3471 grub_strncpy((char *)data, filename, 128);
3472 return 1;
3473 }
3474 }
3475 pos++;
3476 }
3477 }
3478
3479 return 0;
3480 }
3481
3482 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3483 {
3484 int rc = 1;
3485 char *device_name = NULL;
3486 grub_device_t dev = NULL;
3487 grub_fs_t fs = NULL;
3488 char buf[128] = {0};
3489
3490 (void)ctxt;
3491
3492 if (argc != 3)
3493 {
3494 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3495 return 1;
3496 }
3497
3498 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3499
3500 device_name = grub_file_get_device_name(args[0]);
3501 if (!device_name)
3502 {
3503 debug("grub_file_get_device_name failed, %s\n", args[0]);
3504 goto end;
3505 }
3506
3507 dev = grub_device_open(device_name);
3508 if (!dev)
3509 {
3510 debug("grub_device_open failed, %s\n", device_name);
3511 goto end;
3512 }
3513
3514 fs = grub_fs_probe(dev);
3515 if (!fs)
3516 {
3517 debug("grub_fs_probe failed, %s\n", device_name);
3518 goto end;
3519 }
3520
3521 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3522
3523 if (buf[0])
3524 {
3525 ventoy_set_env(args[2], buf);
3526 }
3527
3528 rc = 0;
3529
3530 end:
3531
3532 check_free(device_name, grub_free);
3533 check_free(dev, grub_device_close);
3534
3535 return rc;
3536 }
3537
3538 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3539 {
3540 char name[64];
3541 int ret;
3542 grub_disk_t disk;
3543 grub_device_t dev;
3544
3545 (void)argc;
3546 (void)ctxt;
3547
3548 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3549 if (!g_ventoy_part_info)
3550 {
3551 return 1;
3552 }
3553
3554 disk = grub_disk_open(args[0]);
3555 if (!disk)
3556 {
3557 debug("Failed to open disk %s\n", args[0]);
3558 return 1;
3559 }
3560
3561 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
3562
3563 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3564 grub_disk_close(disk);
3565
3566 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3567 dev = grub_device_open(name);
3568 if (dev)
3569 {
3570 /* make sure that we are running in a correct Ventoy device */
3571 ret = ventoy_check_device(dev);
3572 grub_device_close(dev);
3573
3574 if (ret)
3575 {
3576 grub_exit();
3577 }
3578 }
3579
3580 return 0;
3581 }
3582
3583 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3584 {
3585 int id;
3586 grub_uint8_t zeroguid[16] = {0};
3587
3588 (void)argc;
3589 (void)ctxt;
3590
3591 id = (int)grub_strtoul(args[0], NULL, 10);
3592 grub_errno = 0;
3593
3594 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3595 {
3596 if (id >= 1 && id <= 128)
3597 {
3598 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3599 {
3600 return 0;
3601 }
3602 }
3603 }
3604 else
3605 {
3606 if (id >= 1 && id <= 4)
3607 {
3608 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3609 {
3610 return 0;
3611 }
3612 }
3613 }
3614
3615 return 1;
3616 }
3617
3618 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3619 {
3620 int rc = 1;
3621 char *device_name = NULL;
3622 grub_device_t dev = NULL;
3623 grub_fs_t fs = NULL;
3624 char *label = NULL;
3625
3626 (void)ctxt;
3627
3628 if (argc != 2)
3629 {
3630 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3631 return 1;
3632 }
3633
3634 device_name = grub_file_get_device_name(args[0]);
3635 if (!device_name)
3636 {
3637 debug("grub_file_get_device_name failed, %s\n", args[0]);
3638 goto end;
3639 }
3640
3641 dev = grub_device_open(device_name);
3642 if (!dev)
3643 {
3644 debug("grub_device_open failed, %s\n", device_name);
3645 goto end;
3646 }
3647
3648 fs = grub_fs_probe(dev);
3649 if (!fs)
3650 {
3651 debug("grub_fs_probe failed, %s\n", device_name);
3652 goto end;
3653 }
3654
3655 fs->fs_label(dev, &label);
3656 if (label)
3657 {
3658 ventoy_set_env(args[1], label);
3659 grub_free(label);
3660 }
3661
3662 rc = 0;
3663
3664 end:
3665
3666 check_free(device_name, grub_free);
3667 check_free(dev, grub_device_close);
3668
3669 return rc;
3670 }
3671
3672 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3673 {
3674 if (!info->dir)
3675 {
3676 grub_snprintf((char *)data, 256, "%s", filename);
3677 return 1;
3678 }
3679
3680 return 0;
3681 }
3682
3683
3684 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3685 {
3686 int rc = 1;
3687 char *device_name = NULL;
3688 grub_device_t dev = NULL;
3689 grub_fs_t fs = NULL;
3690 char name[256] ={0};
3691
3692 (void)ctxt;
3693
3694 if (argc != 3)
3695 {
3696 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3697 return 1;
3698 }
3699
3700 device_name = grub_file_get_device_name(args[0]);
3701 if (!device_name)
3702 {
3703 debug("grub_file_get_device_name failed, %s\n", args[0]);
3704 goto end;
3705 }
3706
3707 dev = grub_device_open(device_name);
3708 if (!dev)
3709 {
3710 debug("grub_device_open failed, %s\n", device_name);
3711 goto end;
3712 }
3713
3714 fs = grub_fs_probe(dev);
3715 if (!fs)
3716 {
3717 debug("grub_fs_probe failed, %s\n", device_name);
3718 goto end;
3719 }
3720
3721 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3722 if (name[0])
3723 {
3724 ventoy_set_env(args[2], name);
3725 }
3726
3727 rc = 0;
3728
3729 end:
3730
3731 check_free(device_name, grub_free);
3732 check_free(dev, grub_device_close);
3733
3734 return rc;
3735 }
3736
3737 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3738 {
3739 char c;
3740 char *pos = NULL;
3741 char *end = NULL;
3742
3743 (void)ctxt;
3744
3745 if (argc != 2)
3746 {
3747 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3748 return 1;
3749 }
3750
3751 for (pos = args[0]; *pos; pos++)
3752 {
3753 if (*pos == '.')
3754 {
3755 end = pos;
3756 }
3757 }
3758
3759 if (end)
3760 {
3761 c = *end;
3762 *end = 0;
3763 }
3764
3765 grub_env_set(args[1], args[0]);
3766
3767 if (end)
3768 {
3769 *end = c;
3770 }
3771
3772 return 0;
3773 }
3774
3775 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3776 {
3777 struct grub_video_mode_info info;
3778 char buf[32];
3779
3780 (void)ctxt;
3781 (void)argc;
3782 (void)args;
3783
3784 if (!g_video_mode_list)
3785 {
3786 ventoy_enum_video_mode();
3787 }
3788
3789 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3790 {
3791 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3792 }
3793 else
3794 {
3795 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3796 }
3797
3798 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3799
3800 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3801 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3802
3803 VENTOY_CMD_RETURN(0);
3804 }
3805
3806 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3807 {
3808 struct grub_video_mode_info info;
3809 char buf[32];
3810
3811 (void)ctxt;
3812 (void)argc;
3813 (void)args;
3814
3815 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3816 {
3817 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
3818 }
3819 else
3820 {
3821 grub_snprintf(buf, sizeof(buf), "0x0x0");
3822 }
3823
3824 grub_env_set(args[0], buf);
3825
3826 VENTOY_CMD_RETURN(0);
3827 }
3828
3829 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3830 {
3831 int id;
3832 char buf[32];
3833
3834 (void)ctxt;
3835 (void)argc;
3836
3837 if (!g_video_mode_list)
3838 {
3839 return 0;
3840 }
3841
3842 id = (int)grub_strtoul(args[0], NULL, 10);
3843 if (id < g_video_mode_num)
3844 {
3845 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
3846 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
3847 }
3848
3849 grub_env_set(args[1], buf);
3850
3851 VENTOY_CMD_RETURN(0);
3852 }
3853
3854 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
3855 {
3856 grub_uint64_t size = 0;
3857 grub_file_t file;
3858 va_list ap;
3859 char fullpath[256] = {0};
3860
3861 va_start (ap, fmt);
3862 grub_vsnprintf(fullpath, 255, fmt, ap);
3863 va_end (ap);
3864
3865 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
3866 if (!file)
3867 {
3868 debug("grub_file_open failed <%s>\n", fullpath);
3869 grub_errno = 0;
3870 return 0;
3871 }
3872
3873 size = file->size;
3874 grub_file_close(file);
3875 return size;
3876 }
3877
3878 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
3879 {
3880 va_list ap;
3881 grub_file_t file;
3882 char fullpath[256] = {0};
3883
3884 va_start (ap, fmt);
3885 grub_vsnprintf(fullpath, 255, fmt, ap);
3886 va_end (ap);
3887
3888 file = grub_file_open(fullpath, type);
3889 if (!file)
3890 {
3891 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
3892 grub_errno = 0;
3893 }
3894
3895 return file;
3896 }
3897
3898 int ventoy_is_file_exist(const char *fmt, ...)
3899 {
3900 va_list ap;
3901 int len;
3902 char *pos = NULL;
3903 char buf[256] = {0};
3904
3905 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
3906 pos = buf + 6;
3907
3908 va_start (ap, fmt);
3909 len = grub_vsnprintf(pos, 255, fmt, ap);
3910 va_end (ap);
3911
3912 grub_strncpy(pos + len, "\" ]", 3);
3913
3914 debug("script exec %s\n", buf);
3915
3916 if (0 == grub_script_execute_sourcecode(buf))
3917 {
3918 return 1;
3919 }
3920
3921 return 0;
3922 }
3923
3924 int ventoy_is_dir_exist(const char *fmt, ...)
3925 {
3926 va_list ap;
3927 int len;
3928 char *pos = NULL;
3929 char buf[256] = {0};
3930
3931 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
3932 pos = buf + 6;
3933
3934 va_start (ap, fmt);
3935 len = grub_vsnprintf(pos, 255, fmt, ap);
3936 va_end (ap);
3937
3938 grub_strncpy(pos + len, "\" ]", 3);
3939
3940 debug("script exec %s\n", buf);
3941
3942 if (0 == grub_script_execute_sourcecode(buf))
3943 {
3944 return 1;
3945 }
3946
3947 return 0;
3948 }
3949
3950 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
3951 {
3952 mz_stream s;
3953 grub_uint8_t *outbuf;
3954 grub_uint8_t gzHdr[10] =
3955 {
3956 0x1F, 0x8B, /* magic */
3957 8, /* z method */
3958 0, /* flags */
3959 0,0,0,0, /* mtime */
3960 4, /* xfl */
3961 3, /* OS */
3962 };
3963
3964 grub_memset(&s, 0, sizeof(mz_stream));
3965
3966 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
3967
3968 outbuf = (grub_uint8_t *)mem_out;
3969
3970 mem_out_len -= sizeof(gzHdr) + 8;
3971 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
3972 outbuf += sizeof(gzHdr);
3973
3974 s.avail_in = mem_in_len;
3975 s.next_in = mem_in;
3976
3977 s.avail_out = mem_out_len;
3978 s.next_out = outbuf;
3979
3980 mz_deflate(&s, MZ_FINISH);
3981
3982 mz_deflateEnd(&s);
3983
3984 outbuf += s.total_out;
3985 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
3986 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
3987
3988 return s.total_out + sizeof(gzHdr) + 8;
3989 }
3990
3991 static int ventoy_env_init(void)
3992 {
3993 char buf[64];
3994
3995 grub_env_set("vtdebug_flag", "");
3996
3997 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
3998 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
3999 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4000 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4001
4002 ventoy_filt_register(0, ventoy_wrapper_open);
4003
4004 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4005 if (g_grub_param)
4006 {
4007 g_grub_param->grub_env_get = grub_env_get;
4008 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4009 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4010 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4011 grub_env_set("env_param", buf);
4012 grub_env_set("ventoy_env_param", buf);
4013 grub_env_export("ventoy_env_param");
4014 }
4015
4016 return 0;
4017 }
4018
4019 static cmd_para ventoy_cmds[] =
4020 {
4021 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4022 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4023 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4024 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4025 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4026 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4027 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4028 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4029 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4030 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4031 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4032 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4033 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4034 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4035 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4036 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4037 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4038 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4039 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4040 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4041
4042 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4043 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4044 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4045 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4046 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4047 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4048 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4049
4050 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4051 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4052 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4053 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4054 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4055 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4056 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4057 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4058
4059
4060 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4061 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4062 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4063 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4064 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4065 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4066 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4067 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4068 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4069 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4070 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4071
4072 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4073 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4074 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4075 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4076 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4077 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4078
4079 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4080 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4081 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4082 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4083 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4084 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4085 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4086 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4087 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4088 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4089
4090 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4091 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4092 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4093 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4094 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4095 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4096 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4097 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4098
4099 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4100 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4101 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4102
4103
4104 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4105 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4106 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4107
4108 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4109 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4110 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4111
4112
4113 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4114 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4115 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4116 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4117 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4118 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4119 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4120 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4121 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4122 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4123
4124 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4125 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4126 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4127
4128 };
4129
4130
4131
4132 GRUB_MOD_INIT(ventoy)
4133 {
4134 grub_uint32_t i;
4135 cmd_para *cur = NULL;
4136
4137 ventoy_env_init();
4138
4139 ventoy_arch_mode_init();
4140
4141 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4142 {
4143 cur = ventoy_cmds + i;
4144 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4145 cur->summary, cur->description, cur->parser);
4146 }
4147 }
4148
4149 GRUB_MOD_FINI(ventoy)
4150 {
4151 grub_uint32_t i;
4152
4153 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4154 {
4155 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4156 }
4157 }
4158