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