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