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