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