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