]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
6e8c28e6b86abdd125104a4c86a152c5aedcf48a
[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 if (g_plugin_image_list)
1024 {
1025 return (img1->plugin_list_index - img2->plugin_list_index);
1026 }
1027
1028 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1029 {
1030 c1 = *s1;
1031 c2 = *s2;
1032
1033 if (0 == g_sort_case_sensitive)
1034 {
1035 if (grub_islower(c1))
1036 {
1037 c1 = c1 - 'a' + 'A';
1038 }
1039
1040 if (grub_islower(c2))
1041 {
1042 c2 = c2 - 'a' + 'A';
1043 }
1044 }
1045
1046 if (c1 != c2)
1047 {
1048 break;
1049 }
1050 }
1051
1052 return (c1 - c2);
1053 }
1054
1055 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1056 {
1057 char *s1, *s2;
1058 int c1 = 0;
1059 int c2 = 0;
1060
1061 if (g_plugin_image_list)
1062 {
1063 return (node1->plugin_list_index - node2->plugin_list_index);
1064 }
1065
1066 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1067 {
1068 c1 = *s1;
1069 c2 = *s2;
1070
1071 if (0 == g_sort_case_sensitive)
1072 {
1073 if (grub_islower(c1))
1074 {
1075 c1 = c1 - 'a' + 'A';
1076 }
1077
1078 if (grub_islower(c2))
1079 {
1080 c2 = c2 - 'a' + 'A';
1081 }
1082 }
1083
1084 if (c1 != c2)
1085 {
1086 break;
1087 }
1088 }
1089
1090 return (c1 - c2);
1091 }
1092
1093 void ventoy_swap_img(img_info *img1, img_info *img2)
1094 {
1095 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1096
1097 grub_memcpy(img1, img2, sizeof(img_info));
1098 img1->next = g_img_swap_tmp.next;
1099 img1->prev = g_img_swap_tmp.prev;
1100
1101 g_img_swap_tmp.next = img2->next;
1102 g_img_swap_tmp.prev = img2->prev;
1103 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1104 }
1105
1106 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1107 {
1108 grub_size_t i;
1109
1110 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1111 {
1112 return 0;
1113 }
1114
1115 for (i = 0; i < namelen; i++)
1116 {
1117 if (filename[i] == ' ' || filename[i] == '\t')
1118 {
1119 return 0;
1120 }
1121
1122 if ((grub_uint8_t)(filename[i]) >= 127)
1123 {
1124 return 0;
1125 }
1126 }
1127
1128 return 1;
1129 }
1130
1131 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
1132 {
1133 if (0 == info->dir)
1134 {
1135 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
1136 {
1137 *((int *)data) = 1;
1138 return 0;
1139 }
1140 }
1141
1142 return 0;
1143 }
1144
1145 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1146 {
1147 int i = 0;
1148 int type = 0;
1149 int ignore = 0;
1150 int index = 0;
1151 grub_size_t len;
1152 img_info *img;
1153 img_info *tail;
1154 img_iterator_node *tmp;
1155 img_iterator_node *new_node;
1156 img_iterator_node *node = (img_iterator_node *)data;
1157
1158 len = grub_strlen(filename);
1159
1160 if (info->dir)
1161 {
1162 if ((len == 1 && filename[0] == '.') ||
1163 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1164 {
1165 return 0;
1166 }
1167
1168 if (!ventoy_img_name_valid(filename, len))
1169 {
1170 return 0;
1171 }
1172
1173 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1174 {
1175 return 0;
1176 }
1177
1178 if (g_plugin_image_list)
1179 {
1180 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1181 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1182 if (index == 0)
1183 {
1184 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1185 return 0;
1186 }
1187 }
1188
1189 new_node = grub_zalloc(sizeof(img_iterator_node));
1190 if (new_node)
1191 {
1192 new_node->plugin_list_index = index;
1193 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1194
1195 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1196 if (ignore)
1197 {
1198 debug("Directory %s ignored...\n", new_node->dir);
1199 grub_free(new_node);
1200 return 0;
1201 }
1202
1203 new_node->tail = node->tail;
1204
1205 new_node->parent = node;
1206 if (!node->firstchild)
1207 {
1208 node->firstchild = new_node;
1209 }
1210
1211 if (g_img_iterator_tail)
1212 {
1213 g_img_iterator_tail->next = new_node;
1214 g_img_iterator_tail = new_node;
1215 }
1216 else
1217 {
1218 g_img_iterator_head.next = new_node;
1219 g_img_iterator_tail = new_node;
1220 }
1221 }
1222 }
1223 else
1224 {
1225 debug("Find a file %s\n", filename);
1226 if (len < 4)
1227 {
1228 return 0;
1229 }
1230
1231 if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
1232 {
1233 type = img_type_iso;
1234 }
1235 else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1236 {
1237 type = img_type_wim;
1238 }
1239 else if (g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1240 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1241 {
1242 type = img_type_vhd;
1243 }
1244 #ifdef GRUB_MACHINE_EFI
1245 else if (0 == grub_strcasecmp(filename + len - 4, ".efi"))
1246 {
1247 type = img_type_efi;
1248 }
1249 #endif
1250 else if (0 == grub_strcasecmp(filename + len - 4, ".img"))
1251 {
1252 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1253 {
1254 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1255 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1256 {
1257 return 0;
1258 }
1259 }
1260 type = img_type_img;
1261 }
1262 else if (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1263 {
1264 type = img_type_vtoy;
1265 }
1266 else
1267 {
1268 return 0;
1269 }
1270
1271 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1272 {
1273 return 0;
1274 }
1275
1276 if (g_plugin_image_list)
1277 {
1278 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1279 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1280 if (index == 0)
1281 {
1282 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1283 return 0;
1284 }
1285 }
1286
1287 img = grub_zalloc(sizeof(img_info));
1288 if (img)
1289 {
1290 img->type = type;
1291 img->plugin_list_index = index;
1292 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1293
1294 for (i = 0; i < (int)len; i++)
1295 {
1296 if (filename[i] == ' ' || filename[i] == '\t' || (0 == grub_isprint(filename[i])))
1297 {
1298 img->name[i] = '*';
1299 img->unsupport = 1;
1300 }
1301 }
1302
1303 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1304
1305 img->size = info->size;
1306 if (0 == img->size)
1307 {
1308 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1309 }
1310
1311 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1312 {
1313 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1314 grub_free(img);
1315 return 0;
1316 }
1317
1318 if (g_ventoy_img_list)
1319 {
1320 tail = *(node->tail);
1321 img->prev = tail;
1322 tail->next = img;
1323 }
1324 else
1325 {
1326 g_ventoy_img_list = img;
1327 }
1328
1329 img->id = g_ventoy_img_count;
1330 img->parent = node;
1331 if (node && NULL == node->firstiso)
1332 {
1333 node->firstiso = img;
1334 }
1335
1336 node->isocnt++;
1337 tmp = node->parent;
1338 while (tmp)
1339 {
1340 tmp->isocnt++;
1341 tmp = tmp->parent;
1342 }
1343
1344 *((img_info **)(node->tail)) = img;
1345 g_ventoy_img_count++;
1346
1347 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1348 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name);
1349 if (!img->class)
1350 {
1351 img->class = g_menu_class[type];
1352 }
1353 img->menu_prefix = g_menu_prefix[type];
1354
1355 if (img_type_iso == type)
1356 {
1357 if (ventoy_plugin_check_memdisk(img->path))
1358 {
1359 img->menu_prefix = "miso";
1360 }
1361 }
1362
1363 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1364 }
1365 }
1366
1367 return 0;
1368 }
1369
1370 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1371 {
1372 int len = GRUB_UINT_MAX;
1373 const char *value = NULL;
1374 char name[32] = {0};
1375 char plat[32] = {0};
1376 char guidstr[32] = {0};
1377 ventoy_guid guid = VENTOY_GUID;
1378 const char *fmt1 = NULL;
1379 const char *fmt2 = NULL;
1380 const char *fmt3 = NULL;
1381 grub_uint32_t *puint = (grub_uint32_t *)name;
1382 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1383 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1384 const char fmtcode[]={
1385 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1386 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1387 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1388 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1389 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1390 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1391 };
1392
1393 grub_memset(name, 0, sizeof(name));
1394 puint[0] = grub_swap_bytes32(0x56454e54);
1395 puint[3] = grub_swap_bytes32(0x4f4e0000);
1396 puint[2] = grub_swap_bytes32(0x45525349);
1397 puint[1] = grub_swap_bytes32(0x4f595f56);
1398 value = ventoy_get_env(name);
1399
1400 grub_memset(name, 0, sizeof(name));
1401 puint[1] = grub_swap_bytes32(0x5f544f50);
1402 puint[0] = grub_swap_bytes32(0x56544c45);
1403 fmt1 = ventoy_get_env(name);
1404 if (!fmt1)
1405 {
1406 fmt1 = fmtdata;
1407 }
1408
1409 grub_memset(name, 0, sizeof(name));
1410 puint[1] = grub_swap_bytes32(0x5f4c4654);
1411 puint[0] = grub_swap_bytes32(0x56544c45);
1412 fmt2 = ventoy_get_env(name);
1413
1414 grub_memset(name, 0, sizeof(name));
1415 puint[1] = grub_swap_bytes32(0x5f434c52);
1416 puint[0] = grub_swap_bytes32(0x56544c45);
1417 fmt3 = ventoy_get_env(name);
1418
1419 grub_memcpy(guidstr, &guid, sizeof(guid));
1420
1421 #if defined (GRUB_MACHINE_EFI)
1422 puint2[0] = grub_swap_bytes32(0x55454649);
1423 #else
1424 puint2[0] = grub_swap_bytes32(0x42494f53);
1425 #endif
1426
1427 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1428 #pragma GCC diagnostic push
1429 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1430 len = grub_snprintf(buffer, buflen, fmtcode,
1431 fmt1 ? fmt1 : fmtdata,
1432 fmt2 ? fmt2 : fmtdata + 4,
1433 value ? value : "", plat, guidstr,
1434 fmt3 ? fmt3 : fmtdata + 6);
1435 #pragma GCC diagnostic pop
1436
1437 grub_memset(name, 0, sizeof(name));
1438 puint[0] = grub_swap_bytes32(0x76746f79);
1439 puint[2] = grub_swap_bytes32(0x656e7365);
1440 puint[1] = grub_swap_bytes32(0x5f6c6963);
1441 ventoy_set_env(name, guidstr);
1442
1443 return len;
1444 }
1445
1446 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1447 {
1448 img_info *minimg = NULL;
1449 img_info *img = (img_info *)(node->firstiso);
1450
1451 while (img && (img_iterator_node *)(img->parent) == node)
1452 {
1453 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1454 {
1455 minimg = img;
1456 }
1457 img = img->next;
1458 }
1459
1460 if (minimg)
1461 {
1462 minimg->select = 1;
1463 }
1464
1465 return minimg;
1466 }
1467
1468 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1469 {
1470 img_iterator_node *Minchild = NULL;
1471 img_iterator_node *child = node->firstchild;
1472
1473 while (child && child->parent == node)
1474 {
1475 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
1476 {
1477 Minchild = child;
1478 }
1479 child = child->next;
1480 }
1481
1482 if (Minchild)
1483 {
1484 Minchild->select = 1;
1485 }
1486
1487 return Minchild;
1488 }
1489
1490 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1491 {
1492 int offset = 1;
1493 img_info *img = NULL;
1494 const char *dir_class = NULL;
1495 const char *dir_alias = NULL;
1496 img_iterator_node *child = NULL;
1497
1498 if (node->isocnt == 0 || node->done == 1)
1499 {
1500 return 0;
1501 }
1502
1503 if (node->parent && node->parent->dirlen < node->dirlen)
1504 {
1505 offset = node->parent->dirlen;
1506 }
1507
1508 if (node == &g_img_iterator_head)
1509 {
1510 if (g_default_menu_mode == 0)
1511 {
1512 if (g_tree_view_menu_style == 0)
1513 {
1514 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1515 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1516 " echo 'return ...' \n"
1517 "}\n", "<--");
1518 }
1519 else
1520 {
1521 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1522 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1523 " echo '%s ...' \n"
1524 "}\n", "return");
1525 }
1526 }
1527 }
1528 else
1529 {
1530 node->dir[node->dirlen - 1] = 0;
1531 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1532 if (!dir_class)
1533 {
1534 dir_class = "vtoydir";
1535 }
1536
1537 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1538 if (dir_alias)
1539 {
1540 if (g_tree_view_menu_style == 0)
1541 {
1542 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1543 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1544 "DIR", dir_alias, dir_class, node->dir + offset);
1545 }
1546 else
1547 {
1548 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1549 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1550 dir_alias, dir_class, node->dir + offset);
1551 }
1552 }
1553 else
1554 {
1555 dir_alias = node->dir + offset;
1556
1557 if (g_tree_view_menu_style == 0)
1558 {
1559 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1560 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1561 "DIR", dir_alias, dir_class, node->dir + offset);
1562 }
1563 else
1564 {
1565 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1566 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1567 dir_alias, dir_class, node->dir + offset);
1568 }
1569 }
1570
1571 if (g_tree_view_menu_style == 0)
1572 {
1573 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1574 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1575 " echo 'return ...' \n"
1576 "}\n", "<--");
1577 }
1578 else
1579 {
1580 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1581 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1582 " echo '%s ...' \n"
1583 "}\n", "return");
1584 }
1585 }
1586
1587 while ((child = ventoy_get_min_child(node)) != NULL)
1588 {
1589 ventoy_dynamic_tree_menu(child);
1590 }
1591
1592 while ((img = ventoy_get_min_iso(node)) != NULL)
1593 {
1594 if (g_tree_view_menu_style == 0)
1595 {
1596 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1597 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1598 " %s_%s \n"
1599 "}\n",
1600 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1601 img->unsupport ? "[***********] " : "",
1602 img->alias ? img->alias : img->name, img->class, img->id,
1603 img->menu_prefix,
1604 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1605 }
1606 else
1607 {
1608 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1609 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1610 " %s_%s \n"
1611 "}\n",
1612 img->unsupport ? "[***********] " : "",
1613 img->alias ? img->alias : img->name, img->class, img->id,
1614 img->menu_prefix,
1615 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1616 }
1617 }
1618
1619 if (node != &g_img_iterator_head)
1620 {
1621 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1622 }
1623
1624 node->done = 1;
1625 return 0;
1626 }
1627
1628 int ventoy_check_device_result(int ret)
1629 {
1630 char buf[32];
1631
1632 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
1633 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
1634 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1635
1636 if (ret & 0x1000)
1637 {
1638 grub_printf(VTOY_WARNING"\n");
1639 grub_printf(VTOY_WARNING"\n");
1640 grub_printf(VTOY_WARNING"\n\n\n");
1641
1642 grub_printf("Unsatisfied conditions detected for Ventoy.\n\n");
1643 grub_printf("This is NOT a standard Ventoy device and is NOT officially supported.\n\n");
1644 grub_printf("Recommend to follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1645
1646 grub_printf("\n\nWill exit after 10 seconds ...... ");
1647 grub_refresh();
1648 grub_sleep(10);
1649 }
1650
1651 return ret;
1652 }
1653
1654 int ventoy_check_device(grub_device_t dev)
1655 {
1656 grub_file_t file;
1657 grub_uint64_t offset;
1658 char devname[64];
1659 grub_fs_t fs;
1660 grub_device_t dev2;
1661 char *label = NULL;
1662 struct grub_partition *partition;
1663
1664 if (dev->disk == NULL || dev->disk->partition == NULL)
1665 {
1666 return ventoy_check_device_result(1 | 0x1000);
1667 }
1668
1669 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
1670 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
1671 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_64", dev->disk->name))
1672 {
1673 return ventoy_check_device_result(2 | 0x1000);
1674 }
1675
1676 /* We must have partition 2 */
1677 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
1678 if (!file)
1679 {
1680 return ventoy_check_device_result(3 | 0x1000);
1681 }
1682
1683 if (NULL == grub_strstr(file->fs->name, "fat"))
1684 {
1685 grub_file_close(file);
1686 return ventoy_check_device_result(4 | 0x1000);
1687 }
1688
1689 partition = dev->disk->partition;
1690 if (partition->number != 0 || partition->start != 2048)
1691 {
1692 return ventoy_check_device_result(5);
1693 }
1694
1695 offset = partition->start + partition->len;
1696 partition = file->device->disk->partition;
1697 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
1698 {
1699 grub_file_close(file);
1700 return ventoy_check_device_result(6);
1701 }
1702 grub_file_close(file);
1703
1704 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
1705 dev2 = grub_device_open(devname);
1706 if (!dev2)
1707 {
1708 return ventoy_check_device_result(7);
1709 }
1710
1711 fs = grub_fs_probe(dev2);
1712 if (!fs)
1713 {
1714 grub_device_close(dev2);
1715 return ventoy_check_device_result(8);
1716 }
1717
1718 fs->fs_label(dev2, &label);
1719 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
1720 {
1721 grub_device_close(dev2);
1722 return ventoy_check_device_result(9);
1723 }
1724
1725 grub_device_close(dev2);
1726 return ventoy_check_device_result(0);
1727 }
1728
1729 static int ventoy_set_default_menu(void)
1730 {
1731 int img_len = 0;
1732 char *pos = NULL;
1733 char *end = NULL;
1734 char *def = NULL;
1735 const char *strdata = NULL;
1736 img_info *cur = NULL;
1737 img_info *default_node = NULL;
1738 const char *default_image = NULL;
1739
1740 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1741 if (default_image && default_image[0] == '/')
1742 {
1743 img_len = grub_strlen(default_image);
1744
1745 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1746 {
1747 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1748 {
1749 default_node = cur;
1750 break;
1751 }
1752 }
1753
1754 if (!default_node)
1755 {
1756 return 1;
1757 }
1758
1759 if (0 == g_default_menu_mode)
1760 {
1761 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1762 }
1763 else
1764 {
1765 def = grub_strdup(default_image);
1766 if (!def)
1767 {
1768 return 1;
1769 }
1770
1771 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
1772
1773 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1774 if (strdata && strdata[0] == '/')
1775 {
1776 pos = def + grub_strlen(strdata);
1777 if (*pos == '/')
1778 {
1779 pos++;
1780 }
1781 }
1782 else
1783 {
1784 pos = def + 1;
1785 }
1786
1787 while ((end = grub_strchr(pos, '/')) != NULL)
1788 {
1789 *end = 0;
1790 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
1791 pos = end + 1;
1792 }
1793
1794 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id);
1795 grub_free(def);
1796 }
1797 }
1798
1799 return 0;
1800 }
1801
1802 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1803 {
1804 int len;
1805 grub_fs_t fs;
1806 grub_device_t dev = NULL;
1807 img_info *cur = NULL;
1808 img_info *tail = NULL;
1809 const char *strdata = NULL;
1810 char *device_name = NULL;
1811 char buf[32];
1812 img_iterator_node *node = NULL;
1813 img_iterator_node *tmp = NULL;
1814
1815 (void)ctxt;
1816
1817 if (argc != 2)
1818 {
1819 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1820 }
1821
1822 if (g_ventoy_img_list || g_ventoy_img_count)
1823 {
1824 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1825 }
1826
1827 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1828 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1829 {
1830 g_filt_dot_underscore_file = 1;
1831 }
1832
1833 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1834 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1835 {
1836 g_sort_case_sensitive = 1;
1837 }
1838
1839 device_name = grub_file_get_device_name(args[0]);
1840 if (!device_name)
1841 {
1842 goto fail;
1843 }
1844
1845 g_enum_dev = dev = grub_device_open(device_name);
1846 if (!dev)
1847 {
1848 goto fail;
1849 }
1850
1851 g_enum_fs = fs = grub_fs_probe(dev);
1852 if (!fs)
1853 {
1854 goto fail;
1855 }
1856
1857 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1858 {
1859 debug("unsupported fs:<%s>\n", fs->name);
1860 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1861 goto fail;
1862 }
1863
1864 ventoy_set_env("vtoy_iso_fs", fs->name);
1865
1866 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1867 if (strdata && strdata[0] == '1')
1868 {
1869 g_default_menu_mode = 1;
1870 }
1871
1872 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
1873
1874 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
1875
1876 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1877 if (strdata && strdata[0] == '/')
1878 {
1879 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
1880 if (g_img_iterator_head.dir[len - 1] != '/')
1881 {
1882 g_img_iterator_head.dir[len++] = '/';
1883 }
1884 g_img_iterator_head.dirlen = len;
1885 }
1886 else
1887 {
1888 g_img_iterator_head.dirlen = 1;
1889 grub_strcpy(g_img_iterator_head.dir, "/");
1890 }
1891
1892 g_img_iterator_head.tail = &tail;
1893
1894 for (node = &g_img_iterator_head; node; node = node->next)
1895 {
1896 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1897 }
1898
1899 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1900 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1901 {
1902 g_tree_view_menu_style = 1;
1903 }
1904
1905 ventoy_set_default_menu();
1906
1907 for (node = &g_img_iterator_head; node; node = node->next)
1908 {
1909 ventoy_dynamic_tree_menu(node);
1910 }
1911
1912 /* free node */
1913 node = g_img_iterator_head.next;
1914 while (node)
1915 {
1916 tmp = node->next;
1917 grub_free(node);
1918 node = tmp;
1919 }
1920
1921 /* sort image list by image name */
1922 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1923 {
1924 for (tail = cur->next; tail; tail = tail->next)
1925 {
1926 if (ventoy_cmp_img(cur, tail) > 0)
1927 {
1928 ventoy_swap_img(cur, tail);
1929 }
1930 }
1931 }
1932
1933 if (g_default_menu_mode == 1)
1934 {
1935 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1936 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1937 " echo 'return ...' \n"
1938 "}\n", "<--");
1939 }
1940
1941 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1942 {
1943 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1944 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1945 " %s_%s \n"
1946 "}\n",
1947 cur->unsupport ? "[***********] " : "",
1948 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
1949 cur->menu_prefix,
1950 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
1951 }
1952
1953 g_tree_script_buf[g_tree_script_pos] = 0;
1954 g_list_script_buf[g_list_script_pos] = 0;
1955
1956 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1957 grub_env_set(args[1], buf);
1958
1959 fail:
1960
1961 check_free(device_name, grub_free);
1962 check_free(dev, grub_device_close);
1963
1964 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1965 }
1966
1967
1968 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1969 {
1970 img_info *next = NULL;
1971 img_info *cur = g_ventoy_img_list;
1972
1973 (void)ctxt;
1974 (void)argc;
1975 (void)args;
1976
1977 while (cur)
1978 {
1979 next = cur->next;
1980 grub_free(cur);
1981 cur = next;
1982 }
1983
1984 g_ventoy_img_list = NULL;
1985 g_ventoy_img_count = 0;
1986
1987 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1988 }
1989
1990 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1991 {
1992 long img_id = 0;
1993 img_info *cur = g_ventoy_img_list;
1994
1995 (void)ctxt;
1996
1997 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1998 {
1999 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2000 }
2001
2002 img_id = grub_strtol(args[0], NULL, 10);
2003 if (img_id >= g_ventoy_img_count)
2004 {
2005 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2006 }
2007
2008 debug("Find image %ld name \n", img_id);
2009
2010 while (cur && img_id > 0)
2011 {
2012 img_id--;
2013 cur = cur->next;
2014 }
2015
2016 if (!cur)
2017 {
2018 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2019 }
2020
2021 debug("image name is %s\n", cur->name);
2022
2023 grub_env_set(args[1], cur->name);
2024
2025 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2026 }
2027
2028 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2029 {
2030 int img_id = 0;
2031 char value[32];
2032 char *pos = NULL;
2033 const char *id = NULL;
2034 img_info *cur = g_ventoy_img_list;
2035
2036 (void)ctxt;
2037
2038 if (argc < 1 || argc > 2)
2039 {
2040 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2041 }
2042
2043 id = grub_env_get("chosen");
2044
2045 pos = grub_strstr(id, "VID_");
2046 if (pos)
2047 {
2048 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
2049 }
2050 else
2051 {
2052 img_id = (int)grub_strtoul(id, NULL, 10);
2053 }
2054
2055 while (cur)
2056 {
2057 if (img_id == cur->id)
2058 {
2059 break;
2060 }
2061 cur = cur->next;
2062 }
2063
2064 if (!cur)
2065 {
2066 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2067 }
2068
2069 grub_env_set(args[0], cur->path);
2070
2071 if (argc > 1)
2072 {
2073 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2074 grub_env_set(args[1], value);
2075 }
2076
2077 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2078 }
2079
2080 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2081 {
2082 grub_disk_t disk;
2083 char *device_name;
2084 char *pos;
2085 char *pos2;
2086
2087 device_name = grub_file_get_device_name(filename);
2088 if (!device_name)
2089 {
2090 return 1;
2091 }
2092
2093 pos = device_name;
2094 if (pos[0] == '(')
2095 {
2096 pos++;
2097 }
2098
2099 pos2 = grub_strstr(pos, ",");
2100 if (!pos2)
2101 {
2102 pos2 = grub_strstr(pos, ")");
2103 }
2104
2105 if (pos2)
2106 {
2107 *pos2 = 0;
2108 }
2109
2110 disk = grub_disk_open(pos);
2111 if (disk)
2112 {
2113 grub_disk_read(disk, 0, 0x180, 16, guid);
2114 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2115 grub_disk_close(disk);
2116 }
2117 else
2118 {
2119 return 1;
2120 }
2121
2122 grub_free(device_name);
2123 return 0;
2124 }
2125
2126 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2127 {
2128 eltorito_descriptor desc;
2129
2130 grub_memset(&desc, 0, sizeof(desc));
2131 grub_file_seek(file, 17 * 2048);
2132 grub_file_read(file, &desc, sizeof(desc));
2133
2134 if (desc.type != 0 || desc.version != 1)
2135 {
2136 return 0;
2137 }
2138
2139 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2140 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2141 {
2142 return 0;
2143 }
2144
2145 return desc.sector;
2146 }
2147
2148 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2149 {
2150 int i;
2151 int x86count = 0;
2152 grub_uint8_t buf[512];
2153
2154 grub_file_seek(file, sector * 2048);
2155 grub_file_read(file, buf, sizeof(buf));
2156
2157 if (buf[0] == 0x01 && buf[1] == 0xEF)
2158 {
2159 debug("%s efi eltorito in Validation Entry\n", file->name);
2160 return 1;
2161 }
2162
2163 if (buf[0] == 0x01 && buf[1] == 0x00)
2164 {
2165 x86count++;
2166 }
2167
2168 for (i = 64; i < (int)sizeof(buf); i += 32)
2169 {
2170 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2171 {
2172 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2173 return 1;
2174 }
2175
2176 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2177 {
2178 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2179 return 1;
2180 }
2181 }
2182
2183 debug("%s does not contain efi eltorito\n", file->name);
2184 return 0;
2185 }
2186
2187 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2188 {
2189 char *pos;
2190 const char *fs = NULL;
2191 const char *cdprompt = NULL;
2192 grub_uint32_t i;
2193 grub_uint8_t chksum = 0;
2194 grub_disk_t disk;
2195
2196 disk = file->device->disk;
2197 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2198
2199 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2200 param->vtoy_disk_part_id = disk->partition->number + 1;
2201 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2202
2203 pos = grub_strstr(file->name, "/");
2204 if (!pos)
2205 {
2206 pos = file->name;
2207 }
2208
2209 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2210
2211 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2212
2213 param->vtoy_img_size = file->size;
2214
2215 param->vtoy_reserved[0] = g_ventoy_break_level;
2216 param->vtoy_reserved[1] = g_ventoy_debug_level;
2217
2218 param->vtoy_reserved[2] = g_ventoy_chain_type;
2219
2220 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2221 param->vtoy_reserved[4] = 0;
2222 if (g_ventoy_chain_type == 1) /* Windows */
2223 {
2224 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2225 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2226 {
2227 param->vtoy_reserved[4] = 1;
2228 }
2229 }
2230
2231 fs = ventoy_get_env("ventoy_fs_probe");
2232 if (fs && grub_strcmp(fs, "udf") == 0)
2233 {
2234 param->vtoy_reserved[3] = 1;
2235 }
2236
2237 /* calculate checksum */
2238 for (i = 0; i < sizeof(ventoy_os_param); i++)
2239 {
2240 chksum += *((grub_uint8_t *)param + i);
2241 }
2242 param->chksum = (grub_uint8_t)(0x100 - chksum);
2243
2244 return;
2245 }
2246
2247 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2248 {
2249 grub_uint32_t i = 0;
2250 grub_uint64_t total = 0;
2251 ventoy_img_chunk *chunk = NULL;
2252
2253 for (i = 0; i < chunklist->cur_chunk; i++)
2254 {
2255 chunk = chunklist->chunk + i;
2256
2257 if (chunk->disk_start_sector <= start)
2258 {
2259 debug("%u disk start invalid %lu\n", i, (ulong)start);
2260 return 1;
2261 }
2262
2263 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2264 }
2265
2266 if (total != ((file->size + 511) / 512))
2267 {
2268 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
2269 return 1;
2270 }
2271
2272 return 0;
2273 }
2274
2275 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2276 {
2277 int fs_type;
2278 int len;
2279 grub_uint32_t i = 0;
2280 grub_uint32_t sector = 0;
2281 grub_uint32_t count = 0;
2282 grub_off_t size = 0;
2283 grub_off_t read = 0;
2284
2285 fs_type = ventoy_get_fs_type(file->fs->name);
2286 if (fs_type == ventoy_fs_exfat)
2287 {
2288 grub_fat_get_file_chunk(start, file, chunklist);
2289 }
2290 else if (fs_type == ventoy_fs_ext)
2291 {
2292 grub_ext_get_file_chunk(start, file, chunklist);
2293 }
2294 else
2295 {
2296 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2297 file->read_hook_data = chunklist;
2298
2299 for (size = file->size; size > 0; size -= read)
2300 {
2301 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2302 grub_file_read(file, NULL, read);
2303 }
2304
2305 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2306 {
2307 chunklist->chunk[i].disk_start_sector += start;
2308 chunklist->chunk[i].disk_end_sector += start;
2309 }
2310
2311 if (ventoy_fs_udf == fs_type)
2312 {
2313 for (i = 0; i < chunklist->cur_chunk; i++)
2314 {
2315 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2316 chunklist->chunk[i].img_start_sector = sector;
2317 chunklist->chunk[i].img_end_sector = sector + count - 1;
2318 sector += count;
2319 }
2320 }
2321 }
2322
2323 len = (int)grub_strlen(file->name);
2324 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2325 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2326 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2327 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2328 {
2329 for (i = 0; i < chunklist->cur_chunk; i++)
2330 {
2331 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2332 if (count < 4)
2333 {
2334 count = 1;
2335 }
2336 else
2337 {
2338 count >>= 2;
2339 }
2340
2341 chunklist->chunk[i].img_start_sector = sector;
2342 chunklist->chunk[i].img_end_sector = sector + count - 1;
2343 sector += count;
2344 }
2345 }
2346
2347 return 0;
2348 }
2349
2350 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2351 {
2352 int rc;
2353 grub_file_t file;
2354 grub_disk_addr_t start;
2355
2356 (void)ctxt;
2357 (void)argc;
2358
2359 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2360 if (!file)
2361 {
2362 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2363 }
2364
2365 if (g_img_chunk_list.chunk)
2366 {
2367 grub_free(g_img_chunk_list.chunk);
2368 }
2369
2370 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2371 {
2372 grub_file_close(file);
2373 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2374 }
2375
2376 /* get image chunk data */
2377 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2378 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2379 if (NULL == g_img_chunk_list.chunk)
2380 {
2381 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2382 }
2383
2384 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2385 g_img_chunk_list.cur_chunk = 0;
2386
2387 start = file->device->disk->partition->start;
2388
2389 ventoy_get_block_list(file, &g_img_chunk_list, start);
2390
2391 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2392 grub_file_close(file);
2393
2394 if (rc)
2395 {
2396 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2397 }
2398
2399 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2400 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2401 }
2402
2403 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2404 {
2405 int i = 0;
2406 int pos = 0;
2407 char *buf = NULL;
2408 char configfile[128];
2409 install_template *node = NULL;
2410
2411 (void)ctxt;
2412 (void)argc;
2413 (void)args;
2414
2415 debug("select auto installation argc:%d\n", argc);
2416
2417 if (argc < 1)
2418 {
2419 return 0;
2420 }
2421
2422 node = ventoy_plugin_find_install_template(args[0]);
2423 if (!node)
2424 {
2425 debug("Auto install template not found for %s\n", args[0]);
2426 return 0;
2427 }
2428
2429 if (node->autosel >= 0 && node->autosel <= node->templatenum)
2430 {
2431 node->cursel = node->autosel - 1;
2432 debug("Auto install template auto select %d\n", node->autosel);
2433 return 0;
2434 }
2435
2436 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2437 if (!buf)
2438 {
2439 return 0;
2440 }
2441
2442 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
2443 " echo %s\n}\n", "123");
2444
2445 for (i = 0; i < node->templatenum; i++)
2446 {
2447 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2448 " echo 123\n}\n",
2449 node->templatepath[i].path);
2450 }
2451
2452 g_ventoy_menu_esc = 1;
2453 g_ventoy_suppress_esc = 1;
2454
2455 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2456 grub_script_execute_sourcecode(configfile);
2457
2458 g_ventoy_menu_esc = 0;
2459 g_ventoy_suppress_esc = 0;
2460
2461 grub_free(buf);
2462
2463 node->cursel = g_ventoy_last_entry - 1;
2464
2465 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2466 }
2467
2468 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2469 {
2470 int i = 0;
2471 int pos = 0;
2472 char *buf = NULL;
2473 char configfile[128];
2474 persistence_config *node;
2475
2476 (void)ctxt;
2477 (void)argc;
2478 (void)args;
2479
2480 debug("select persistence argc:%d\n", argc);
2481
2482 if (argc < 1)
2483 {
2484 return 0;
2485 }
2486
2487 node = ventoy_plugin_find_persistent(args[0]);
2488 if (!node)
2489 {
2490 debug("Persistence image not found for %s\n", args[0]);
2491 return 0;
2492 }
2493
2494 if (node->autosel >= 0 && node->autosel <= node->backendnum)
2495 {
2496 node->cursel = node->autosel - 1;
2497 debug("Persistence image auto select %d\n", node->autosel);
2498 return 0;
2499 }
2500
2501 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
2502 if (!buf)
2503 {
2504 return 0;
2505 }
2506
2507 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
2508 " echo %s\n}\n", "123");
2509
2510 for (i = 0; i < node->backendnum; i++)
2511 {
2512 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
2513 " echo 123\n}\n",
2514 node->backendpath[i].path);
2515
2516 }
2517
2518 g_ventoy_menu_esc = 1;
2519 g_ventoy_suppress_esc = 1;
2520
2521 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
2522 grub_script_execute_sourcecode(configfile);
2523
2524 g_ventoy_menu_esc = 0;
2525 g_ventoy_suppress_esc = 0;
2526
2527 grub_free(buf);
2528
2529 node->cursel = g_ventoy_last_entry - 1;
2530
2531 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2532 }
2533
2534 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2535 {
2536 grub_uint32_t i;
2537 ventoy_img_chunk *cur;
2538
2539 (void)ctxt;
2540 (void)argc;
2541 (void)args;
2542
2543 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
2544 {
2545 cur = g_img_chunk_list.chunk + i;
2546 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2547 cur->img_start_sector, cur->img_end_sector,
2548 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
2549 );
2550 }
2551
2552 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2553 }
2554
2555 #ifdef GRUB_MACHINE_EFI
2556 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
2557 {
2558 (void)ctxt;
2559 (void)argc;
2560 (void)args;
2561 return 0;
2562 }
2563 #else
2564 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
2565 {
2566 int rc = 0;
2567 ulong chain_len = 0;
2568 char *chain_data = NULL;
2569 char *relocator_addr = NULL;
2570 grub_relocator_chunk_t ch;
2571 struct grub_relocator *relocator = NULL;
2572 char envbuf[64] = { 0 };
2573
2574 (void)ctxt;
2575 (void)argc;
2576 (void)args;
2577
2578 if (argc != 2)
2579 {
2580 return 1;
2581 }
2582
2583 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
2584 chain_len = grub_strtoul(args[1], NULL, 10);
2585
2586 relocator = grub_relocator_new ();
2587 if (!relocator)
2588 {
2589 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
2590 return 1;
2591 }
2592
2593 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
2594 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2595 chain_len);
2596 if (rc)
2597 {
2598 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
2599 grub_relocator_unload (relocator);
2600 return 1;
2601 }
2602
2603 relocator_addr = get_virtual_current_address(ch);
2604
2605 grub_memcpy(relocator_addr, chain_data, chain_len);
2606
2607 grub_relocator_unload (relocator);
2608
2609 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
2610 grub_env_set("vtoy_chain_relocator_addr", envbuf);
2611
2612 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2613 }
2614 #endif
2615
2616 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
2617 {
2618 grub_uint32_t i;
2619 grub_file_t file;
2620 ventoy_img_chunk_list chunklist;
2621
2622 (void)ctxt;
2623 (void)argc;
2624
2625 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2626 if (!file)
2627 {
2628 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2629 }
2630
2631 /* get image chunk data */
2632 grub_memset(&chunklist, 0, sizeof(chunklist));
2633 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2634 if (NULL == chunklist.chunk)
2635 {
2636 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2637 }
2638
2639 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
2640 chunklist.cur_chunk = 0;
2641
2642 ventoy_get_block_list(file, &chunklist, 0);
2643
2644 if (0 != ventoy_check_block_list(file, &chunklist, 0))
2645 {
2646 grub_printf("########## UNSUPPORTED ###############\n");
2647 }
2648
2649 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
2650
2651 for (i = 0; i < chunklist.cur_chunk; i++)
2652 {
2653 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
2654 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
2655 }
2656
2657 grub_printf("\n==================================\n");
2658
2659 for (i = 0; i < chunklist.cur_chunk; i++)
2660 {
2661 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
2662 (ulonglong)chunklist.chunk[i].img_start_sector,
2663 (ulonglong)chunklist.chunk[i].img_end_sector,
2664 (ulonglong)chunklist.chunk[i].disk_start_sector,
2665 (ulonglong)chunklist.chunk[i].disk_end_sector
2666 );
2667 }
2668
2669 grub_free(chunklist.chunk);
2670 grub_file_close(file);
2671
2672 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2673 }
2674
2675 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
2676 {
2677 int i;
2678 ventoy_grub_param_file_replace *replace = NULL;
2679
2680 (void)ctxt;
2681 (void)argc;
2682 (void)args;
2683
2684 if (argc >= 2)
2685 {
2686 replace = &(g_grub_param->file_replace);
2687 replace->magic = GRUB_FILE_REPLACE_MAGIC;
2688
2689 replace->old_name_cnt = 0;
2690 for (i = 0; i < 4 && i + 1 < argc; i++)
2691 {
2692 replace->old_name_cnt++;
2693 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
2694 }
2695
2696 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
2697 }
2698
2699 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2700 }
2701
2702 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2703 {
2704 (void)ctxt;
2705 (void)argc;
2706 (void)args;
2707
2708 if (argc == 0)
2709 {
2710 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
2711 grub_printf("%s", g_list_script_buf);
2712 }
2713 else
2714 {
2715 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
2716 grub_printf("%s", g_tree_script_buf);
2717 }
2718
2719 return 0;
2720 }
2721
2722 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2723 {
2724 img_info *cur = g_ventoy_img_list;
2725
2726 (void)ctxt;
2727 (void)argc;
2728 (void)args;
2729
2730 while (cur)
2731 {
2732 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
2733 grub_printf("name:<%s>\n\n", cur->name);
2734 cur = cur->next;
2735 }
2736
2737 return 0;
2738 }
2739
2740 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
2741 {
2742 (void)ctxt;
2743 (void)argc;
2744 (void)args;
2745
2746 ventoy_plugin_dump_injection();
2747
2748 return 0;
2749 }
2750
2751 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2752 {
2753 (void)ctxt;
2754 (void)argc;
2755 (void)args;
2756
2757 ventoy_plugin_dump_auto_install();
2758
2759 return 0;
2760 }
2761
2762 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2763 {
2764 (void)ctxt;
2765 (void)argc;
2766 (void)args;
2767
2768 ventoy_plugin_dump_persistence();
2769
2770 return 0;
2771 }
2772
2773 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2774 {
2775 (void)ctxt;
2776 (void)argc;
2777 (void)args;
2778
2779 if (argc != 1)
2780 {
2781 return 1;
2782 }
2783
2784 if (args[0][0] == '0')
2785 {
2786 return g_ventoy_memdisk_mode ? 0 : 1;
2787 }
2788 else if (args[0][0] == '1')
2789 {
2790 return g_ventoy_iso_raw ? 0 : 1;
2791 }
2792 else if (args[0][0] == '2')
2793 {
2794 return g_ventoy_iso_uefi_drv ? 0 : 1;
2795 }
2796
2797 return 1;
2798 }
2799
2800 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2801 {
2802 static int configfile_mode = 0;
2803 char memfile[128] = {0};
2804
2805 (void)ctxt;
2806 (void)argc;
2807 (void)args;
2808
2809 /*
2810 * args[0]: 0:normal 1:configfile
2811 * args[1]: 0:list_buf 1:tree_buf
2812 */
2813
2814 if (argc != 2)
2815 {
2816 debug("Invalid argc %d\n", argc);
2817 return 0;
2818 }
2819
2820 if (args[0][0] == '0')
2821 {
2822 if (args[1][0] == '0')
2823 {
2824 grub_script_execute_sourcecode(g_list_script_buf);
2825 }
2826 else
2827 {
2828 grub_script_execute_sourcecode(g_tree_script_buf);
2829 }
2830 }
2831 else
2832 {
2833 if (configfile_mode)
2834 {
2835 debug("Now already in F3 mode %d\n", configfile_mode);
2836 return 0;
2837 }
2838
2839 if (args[1][0] == '0')
2840 {
2841 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2842 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2843 }
2844 else
2845 {
2846 g_ventoy_last_entry = -1;
2847 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2848 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2849 }
2850
2851 configfile_mode = 1;
2852 grub_script_execute_sourcecode(memfile);
2853 configfile_mode = 0;
2854 }
2855
2856 return 0;
2857 }
2858
2859 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2860 {
2861 grub_file_t file;
2862
2863 (void)ctxt;
2864
2865 if (argc != 1)
2866 {
2867 return 1;
2868 }
2869
2870 g_ventoy_case_insensitive = 1;
2871 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2872 g_ventoy_case_insensitive = 0;
2873
2874 grub_errno = 0;
2875
2876 if (file)
2877 {
2878 grub_file_close(file);
2879 return 0;
2880 }
2881 return 1;
2882 }
2883
2884 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
2885 {
2886 int id = 0;
2887 int find = 0;
2888 grub_disk_t disk;
2889 const char *isopath = NULL;
2890 char hdname[32];
2891 ventoy_mbr_head mbr;
2892
2893 (void)ctxt;
2894 (void)argc;
2895
2896 if (argc != 1)
2897 {
2898 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
2899 }
2900
2901 isopath = grub_env_get("vtoy_iso_part");
2902 if (!isopath)
2903 {
2904 debug("isopath is null %p\n", isopath);
2905 return 0;
2906 }
2907
2908 debug("isopath is %s\n", isopath);
2909
2910 for (id = 0; id < 30 && (find == 0); id++)
2911 {
2912 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
2913 if (grub_strstr(isopath, hdname))
2914 {
2915 debug("skip %s ...\n", hdname);
2916 continue;
2917 }
2918
2919 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
2920
2921 disk = grub_disk_open(hdname);
2922 if (!disk)
2923 {
2924 debug("%s not exist\n", hdname);
2925 break;
2926 }
2927
2928 grub_memset(&mbr, 0, sizeof(mbr));
2929 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
2930 {
2931 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
2932 {
2933 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
2934 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
2935 {
2936
2937 grub_env_set(args[0], hdname);
2938 find = 1;
2939 }
2940 }
2941 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
2942 }
2943 else
2944 {
2945 debug("read %s failed\n", hdname);
2946 }
2947
2948 grub_disk_close(disk);
2949 }
2950
2951 return 0;
2952 }
2953
2954 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
2955 {
2956 int len = 1024;
2957 grub_file_t file;
2958 char *buf = NULL;
2959
2960 (void)ctxt;
2961 (void)argc;
2962
2963 if (argc != 2)
2964 {
2965 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
2966 }
2967
2968 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2969 if (!file)
2970 {
2971 debug("failed to open file %s\n", args[0]);
2972 return 0;
2973 }
2974
2975 buf = grub_malloc(len);
2976 if (!buf)
2977 {
2978 goto end;
2979 }
2980
2981 buf[len - 1] = 0;
2982 grub_file_read(file, buf, len - 1);
2983
2984 ventoy_get_line(buf);
2985 ventoy_set_env(args[1], buf);
2986
2987 end:
2988
2989 grub_check_free(buf);
2990 grub_file_close(file);
2991
2992 return 0;
2993 }
2994
2995 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
2996 {
2997 (void)disk;
2998 (void)data;
2999
3000 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3001 "0 %llu linear /dev/ventoy %llu\n",
3002 (ulonglong)partition->len, (ulonglong)partition->start);
3003
3004 return 0;
3005 }
3006
3007 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3008 {
3009 char *device_name = NULL;
3010 grub_device_t dev = NULL;
3011 char buf[64];
3012
3013 (void)ctxt;
3014
3015 g_part_list_pos = 0;
3016 grub_env_unset("vtoy_img_part_file");
3017
3018 if (argc != 1)
3019 {
3020 return 1;
3021 }
3022
3023 device_name = grub_file_get_device_name(args[0]);
3024 if (!device_name)
3025 {
3026 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3027 goto end;
3028 }
3029
3030 dev = grub_device_open(device_name);
3031 if (!dev)
3032 {
3033 debug("grub_device_open failed, %s\n", device_name);
3034 goto end;
3035 }
3036
3037 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3038
3039 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3040 grub_env_set("vtoy_img_part_file", buf);
3041
3042 end:
3043
3044 check_free(device_name, grub_free);
3045 check_free(dev, grub_device_close);
3046
3047 return 0;
3048 }
3049
3050
3051 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3052 {
3053 int rc = 1;
3054 grub_file_t file;
3055 char *buf = NULL;
3056
3057 (void)ctxt;
3058 (void)argc;
3059
3060 if (argc != 2)
3061 {
3062 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3063 }
3064
3065 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3066 if (!file)
3067 {
3068 debug("failed to open file %s\n", args[0]);
3069 return 1;
3070 }
3071
3072 buf = grub_malloc(file->size + 1);
3073 if (!buf)
3074 {
3075 goto end;
3076 }
3077
3078 buf[file->size] = 0;
3079 grub_file_read(file, buf, file->size);
3080
3081 if (grub_strstr(buf, args[1]))
3082 {
3083 rc = 0;
3084 }
3085
3086 end:
3087
3088 grub_check_free(buf);
3089 grub_file_close(file);
3090
3091 return rc;
3092 }
3093
3094 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3095 {
3096 int len;
3097 grub_file_t file;
3098 char buf[64];
3099 ventoy_iso9660_vd pvd;
3100
3101 (void)ctxt;
3102 (void)argc;
3103
3104 if (argc != 3)
3105 {
3106 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid \n", cmd_raw_name);
3107 }
3108
3109 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3110 if (!file)
3111 {
3112 debug("failed to open file %s\n", args[0]);
3113 return 0;
3114 }
3115
3116 grub_file_seek(file, 16 * 2048);
3117 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3118 if (len != sizeof(pvd))
3119 {
3120 debug("failed to read pvd %d\n", len);
3121 goto end;
3122 }
3123
3124 grub_memset(buf, 0, sizeof(buf));
3125 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3126 ventoy_set_env(args[1], buf);
3127
3128 grub_memset(buf, 0, sizeof(buf));
3129 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3130 ventoy_set_env(args[2], buf);
3131
3132 end:
3133 grub_file_close(file);
3134
3135 return 0;
3136 }
3137
3138 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3139 {
3140 int len;
3141 grub_file_t file;
3142 char buf[64];
3143
3144 (void)ctxt;
3145 (void)argc;
3146
3147 if (argc != 2)
3148 {
3149 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3150 }
3151
3152 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3153 if (!file)
3154 {
3155 debug("failed to open file %s\n", args[0]);
3156 return 0;
3157 }
3158
3159 grub_memset(buf, 0, sizeof(buf));
3160 grub_file_seek(file, 16 * 2048 + 813);
3161 len = (int)grub_file_read(file, buf, 17);
3162 if (len != 17)
3163 {
3164 debug("failed to read create date %d\n", len);
3165 goto end;
3166 }
3167
3168 ventoy_set_env(args[1], buf);
3169
3170 end:
3171 grub_file_close(file);
3172
3173 return 0;
3174 }
3175
3176 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3177 {
3178 (void)ctxt;
3179 (void)argc;
3180 (void)args;
3181
3182 ventoy_env_hook_root(1);
3183
3184 return 0;
3185 }
3186
3187 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3188 {
3189 (void)ctxt;
3190 (void)argc;
3191 (void)args;
3192
3193 ventoy_env_hook_root(0);
3194
3195 return 0;
3196 }
3197
3198 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3199 {
3200 int i;
3201 int buflen;
3202 int datalen;
3203 int loclen;
3204 int img_chunk_num;
3205 int image_sector_size;
3206 char cmd[64];
3207 ventoy_chain_head *chain;
3208 ventoy_img_chunk *chunk;
3209 ventoy_os_param *osparam;
3210 ventoy_image_location *location;
3211 ventoy_image_disk_region *region;
3212 struct grub_acpi_table_header *acpi;
3213
3214 (void)ctxt;
3215
3216 if (argc != 2)
3217 {
3218 return 1;
3219 }
3220
3221 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3222
3223 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3224 if (!chain)
3225 {
3226 return 1;
3227 }
3228
3229 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3230
3231 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3232 {
3233 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3234 return 1;
3235 }
3236
3237 img_chunk_num = chain->img_chunk_num;
3238
3239 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3240 datalen = sizeof(ventoy_os_param) + loclen;
3241
3242 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3243 acpi = grub_zalloc(buflen);
3244 if (!acpi)
3245 {
3246 return 1;
3247 }
3248
3249 /* Step1: Fill acpi table header */
3250 grub_memcpy(acpi->signature, "VTOY", 4);
3251 acpi->length = buflen;
3252 acpi->revision = 1;
3253 grub_memcpy(acpi->oemid, "VENTOY", 6);
3254 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3255 acpi->oemrev = 1;
3256 acpi->creator_id[0] = 1;
3257 acpi->creator_rev = 1;
3258
3259 /* Step2: Fill data */
3260 osparam = (ventoy_os_param *)(acpi + 1);
3261 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3262 osparam->vtoy_img_location_addr = 0;
3263 osparam->vtoy_img_location_len = loclen;
3264 osparam->chksum = 0;
3265 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3266
3267 location = (ventoy_image_location *)(osparam + 1);
3268 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3269 location->image_sector_size = image_sector_size;
3270 location->disk_sector_size = chain->disk_sector_size;
3271 location->region_count = img_chunk_num;
3272
3273 region = location->regions;
3274 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3275 if (512 == image_sector_size)
3276 {
3277 for (i = 0; i < img_chunk_num; i++)
3278 {
3279 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3280 region->image_start_sector = chunk->img_start_sector * 4;
3281 region->disk_start_sector = chunk->disk_start_sector;
3282 region++;
3283 chunk++;
3284 }
3285 }
3286 else
3287 {
3288 for (i = 0; i < img_chunk_num; i++)
3289 {
3290 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3291 region->image_start_sector = chunk->img_start_sector;
3292 region->disk_start_sector = chunk->disk_start_sector;
3293 region++;
3294 chunk++;
3295 }
3296 }
3297
3298 /* Step3: Fill acpi checksum */
3299 acpi->checksum = 0;
3300 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3301
3302 /* load acpi table */
3303 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3304 grub_script_execute_sourcecode(cmd);
3305
3306 grub_free(acpi);
3307
3308 VENTOY_CMD_RETURN(0);
3309 }
3310
3311 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3312 {
3313 (void)ctxt;
3314 (void)argc;
3315 (void)args;
3316
3317 g_ventoy_last_entry_back = g_ventoy_last_entry;
3318 g_ventoy_last_entry = -1;
3319
3320 return 0;
3321 }
3322
3323 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3324 {
3325 (void)ctxt;
3326 (void)argc;
3327 (void)args;
3328
3329 g_ventoy_last_entry = g_ventoy_last_entry_back;
3330
3331 return 0;
3332 }
3333
3334 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3335 {
3336 const char *pos = filename + 1;
3337
3338 if (info->dir)
3339 {
3340 while (*pos)
3341 {
3342 if (*pos == '.')
3343 {
3344 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3345 {
3346 grub_strncpy((char *)data, filename, 128);
3347 return 1;
3348 }
3349 }
3350 pos++;
3351 }
3352 }
3353
3354 return 0;
3355 }
3356
3357 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3358 {
3359 int rc = 1;
3360 char *device_name = NULL;
3361 grub_device_t dev = NULL;
3362 grub_fs_t fs = NULL;
3363 char buf[128] = {0};
3364
3365 (void)ctxt;
3366
3367 if (argc != 3)
3368 {
3369 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3370 return 1;
3371 }
3372
3373 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3374
3375 device_name = grub_file_get_device_name(args[0]);
3376 if (!device_name)
3377 {
3378 debug("grub_file_get_device_name failed, %s\n", args[0]);
3379 goto end;
3380 }
3381
3382 dev = grub_device_open(device_name);
3383 if (!dev)
3384 {
3385 debug("grub_device_open failed, %s\n", device_name);
3386 goto end;
3387 }
3388
3389 fs = grub_fs_probe(dev);
3390 if (!fs)
3391 {
3392 debug("grub_fs_probe failed, %s\n", device_name);
3393 goto end;
3394 }
3395
3396 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
3397
3398 if (buf[0])
3399 {
3400 ventoy_set_env(args[2], buf);
3401 }
3402
3403 rc = 0;
3404
3405 end:
3406
3407 check_free(device_name, grub_free);
3408 check_free(dev, grub_device_close);
3409
3410 return rc;
3411 }
3412
3413 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
3414 {
3415 char name[64];
3416 int ret;
3417 grub_disk_t disk;
3418 grub_device_t dev;
3419
3420 (void)argc;
3421 (void)ctxt;
3422
3423 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
3424 if (!g_ventoy_part_info)
3425 {
3426 return 1;
3427 }
3428
3429 disk = grub_disk_open(args[0]);
3430 if (!disk)
3431 {
3432 debug("Failed to open disk %s\n", args[0]);
3433 return 1;
3434 }
3435
3436 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
3437 grub_disk_close(disk);
3438
3439 grub_snprintf(name, sizeof(name), "%s,1", args[0]);
3440 dev = grub_device_open(name);
3441 if (dev)
3442 {
3443 /* make sure that we are running in a correct Ventoy device */
3444 ret = ventoy_check_device(dev);
3445 grub_device_close(dev);
3446
3447 if (ret & 0x1000)
3448 {
3449 grub_exit();
3450 }
3451 }
3452
3453 return 0;
3454 }
3455
3456 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
3457 {
3458 int id;
3459 grub_uint8_t zeroguid[16] = {0};
3460
3461 (void)argc;
3462 (void)ctxt;
3463
3464 id = (int)grub_strtoul(args[0], NULL, 10);
3465 grub_errno = 0;
3466
3467 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
3468 {
3469 if (id >= 1 && id <= 128)
3470 {
3471 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
3472 {
3473 return 0;
3474 }
3475 }
3476 }
3477 else
3478 {
3479 if (id >= 1 && id <= 4)
3480 {
3481 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
3482 {
3483 return 0;
3484 }
3485 }
3486 }
3487
3488 return 1;
3489 }
3490
3491 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
3492 {
3493 int rc = 1;
3494 char *device_name = NULL;
3495 grub_device_t dev = NULL;
3496 grub_fs_t fs = NULL;
3497 char *label = NULL;
3498
3499 (void)ctxt;
3500
3501 if (argc != 2)
3502 {
3503 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
3504 return 1;
3505 }
3506
3507 device_name = grub_file_get_device_name(args[0]);
3508 if (!device_name)
3509 {
3510 debug("grub_file_get_device_name failed, %s\n", args[0]);
3511 goto end;
3512 }
3513
3514 dev = grub_device_open(device_name);
3515 if (!dev)
3516 {
3517 debug("grub_device_open failed, %s\n", device_name);
3518 goto end;
3519 }
3520
3521 fs = grub_fs_probe(dev);
3522 if (!fs)
3523 {
3524 debug("grub_fs_probe failed, %s\n", device_name);
3525 goto end;
3526 }
3527
3528 fs->fs_label(dev, &label);
3529 if (label)
3530 {
3531 ventoy_set_env(args[1], label);
3532 grub_free(label);
3533 }
3534
3535 rc = 0;
3536
3537 end:
3538
3539 check_free(device_name, grub_free);
3540 check_free(dev, grub_device_close);
3541
3542 return rc;
3543 }
3544
3545 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
3546 {
3547 if (!info->dir)
3548 {
3549 grub_snprintf((char *)data, 256, "%s", filename);
3550 return 1;
3551 }
3552
3553 return 0;
3554 }
3555
3556
3557 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
3558 {
3559 int rc = 1;
3560 char *device_name = NULL;
3561 grub_device_t dev = NULL;
3562 grub_fs_t fs = NULL;
3563 char name[256] ={0};
3564
3565 (void)ctxt;
3566
3567 if (argc != 3)
3568 {
3569 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc);
3570 return 1;
3571 }
3572
3573 device_name = grub_file_get_device_name(args[0]);
3574 if (!device_name)
3575 {
3576 debug("grub_file_get_device_name failed, %s\n", args[0]);
3577 goto end;
3578 }
3579
3580 dev = grub_device_open(device_name);
3581 if (!dev)
3582 {
3583 debug("grub_device_open failed, %s\n", device_name);
3584 goto end;
3585 }
3586
3587 fs = grub_fs_probe(dev);
3588 if (!fs)
3589 {
3590 debug("grub_fs_probe failed, %s\n", device_name);
3591 goto end;
3592 }
3593
3594 fs->fs_dir(dev, args[1], ventoy_fs_enum_1st_file, name);
3595 if (name[0])
3596 {
3597 ventoy_set_env(args[2], name);
3598 }
3599
3600 rc = 0;
3601
3602 end:
3603
3604 check_free(device_name, grub_free);
3605 check_free(dev, grub_device_close);
3606
3607 return rc;
3608 }
3609
3610 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
3611 {
3612 char c;
3613 char *pos = NULL;
3614 char *end = NULL;
3615
3616 (void)ctxt;
3617
3618 if (argc != 2)
3619 {
3620 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
3621 return 1;
3622 }
3623
3624 for (pos = args[0]; *pos; pos++)
3625 {
3626 if (*pos == '.')
3627 {
3628 end = pos;
3629 }
3630 }
3631
3632 if (end)
3633 {
3634 c = *end;
3635 *end = 0;
3636 }
3637
3638 grub_env_set(args[1], args[0]);
3639
3640 if (end)
3641 {
3642 *end = c;
3643 }
3644
3645 return 0;
3646 }
3647
3648 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3649 {
3650 struct grub_video_mode_info info;
3651 char buf[32];
3652
3653 (void)ctxt;
3654 (void)argc;
3655 (void)args;
3656
3657 if (!g_video_mode_list)
3658 {
3659 ventoy_enum_video_mode();
3660 }
3661
3662 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3663 {
3664 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
3665 }
3666 else
3667 {
3668 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
3669 }
3670
3671 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
3672
3673 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
3674 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
3675
3676 VENTOY_CMD_RETURN(0);
3677 }
3678
3679 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3680 {
3681 struct grub_video_mode_info info;
3682 char buf[32];
3683
3684 (void)ctxt;
3685 (void)argc;
3686 (void)args;
3687
3688 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
3689 {
3690 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
3691 }
3692 else
3693 {
3694 grub_snprintf(buf, sizeof(buf), "0x0x0");
3695 }
3696
3697 grub_env_set(args[0], buf);
3698
3699 VENTOY_CMD_RETURN(0);
3700 }
3701
3702 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3703 {
3704 int id;
3705 char buf[32];
3706
3707 (void)ctxt;
3708 (void)argc;
3709
3710 if (!g_video_mode_list)
3711 {
3712 return 0;
3713 }
3714
3715 id = (int)grub_strtoul(args[0], NULL, 10);
3716 if (id < g_video_mode_num)
3717 {
3718 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
3719 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
3720 }
3721
3722 grub_env_set(args[1], buf);
3723
3724 VENTOY_CMD_RETURN(0);
3725 }
3726
3727 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
3728 {
3729 grub_uint64_t size = 0;
3730 grub_file_t file;
3731 va_list ap;
3732 char fullpath[256] = {0};
3733
3734 va_start (ap, fmt);
3735 grub_vsnprintf(fullpath, 255, fmt, ap);
3736 va_end (ap);
3737
3738 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
3739 if (!file)
3740 {
3741 debug("grub_file_open failed <%s>\n", fullpath);
3742 grub_errno = 0;
3743 return 0;
3744 }
3745
3746 size = file->size;
3747 grub_file_close(file);
3748 return size;
3749 }
3750
3751 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
3752 {
3753 va_list ap;
3754 grub_file_t file;
3755 char fullpath[256] = {0};
3756
3757 va_start (ap, fmt);
3758 grub_vsnprintf(fullpath, 255, fmt, ap);
3759 va_end (ap);
3760
3761 file = grub_file_open(fullpath, type);
3762 if (!file)
3763 {
3764 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
3765 grub_errno = 0;
3766 }
3767
3768 return file;
3769 }
3770
3771 int ventoy_is_file_exist(const char *fmt, ...)
3772 {
3773 va_list ap;
3774 int len;
3775 char *pos = NULL;
3776 char buf[256] = {0};
3777
3778 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
3779 pos = buf + 5;
3780
3781 va_start (ap, fmt);
3782 len = grub_vsnprintf(pos, 255, fmt, ap);
3783 va_end (ap);
3784
3785 grub_strncpy(pos + len, " ]", 2);
3786
3787 debug("script exec %s\n", buf);
3788
3789 if (0 == grub_script_execute_sourcecode(buf))
3790 {
3791 return 1;
3792 }
3793
3794 return 0;
3795 }
3796
3797 int ventoy_is_dir_exist(const char *fmt, ...)
3798 {
3799 va_list ap;
3800 int len;
3801 char *pos = NULL;
3802 char buf[256] = {0};
3803
3804 grub_snprintf(buf, sizeof(buf), "%s", "[ -d ");
3805 pos = buf + 5;
3806
3807 va_start (ap, fmt);
3808 len = grub_vsnprintf(pos, 255, fmt, ap);
3809 va_end (ap);
3810
3811 grub_strncpy(pos + len, " ]", 2);
3812
3813 debug("script exec %s\n", buf);
3814
3815 if (0 == grub_script_execute_sourcecode(buf))
3816 {
3817 return 1;
3818 }
3819
3820 return 0;
3821 }
3822
3823 static int ventoy_env_init(void)
3824 {
3825 char buf[64];
3826
3827 grub_env_set("vtdebug_flag", "");
3828
3829 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
3830 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
3831 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
3832
3833 ventoy_filt_register(0, ventoy_wrapper_open);
3834
3835 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
3836 if (g_grub_param)
3837 {
3838 g_grub_param->grub_env_get = grub_env_get;
3839 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
3840 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
3841 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
3842 grub_env_set("env_param", buf);
3843 grub_env_set("ventoy_env_param", buf);
3844 grub_env_export("ventoy_env_param");
3845 }
3846
3847 return 0;
3848 }
3849
3850 static cmd_para ventoy_cmds[] =
3851 {
3852 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
3853 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
3854 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
3855 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
3856 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
3857 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
3858 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
3859 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
3860 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
3861 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
3862 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
3863 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
3864 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
3865 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
3866 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
3867 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
3868 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
3869 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
3870 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
3871 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
3872
3873 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
3874 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
3875 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
3876 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
3877 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
3878 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
3879
3880 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
3881 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
3882 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
3883 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
3884 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
3885 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
3886 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
3887 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
3888
3889
3890 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
3891 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
3892 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
3893 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
3894 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
3895 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
3896 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
3897 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
3898 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
3899 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
3900
3901 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
3902 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
3903 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
3904 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
3905 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
3906 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
3907
3908 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
3909 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
3910 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
3911 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
3912 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
3913 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
3914 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
3915 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
3916 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
3917 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
3918
3919 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
3920 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
3921 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
3922 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
3923 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
3924 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
3925 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
3926
3927 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
3928 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
3929 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
3930 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
3931
3932
3933 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
3934 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
3935
3936 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
3937 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
3938 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
3939
3940
3941 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
3942 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
3943 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
3944 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
3945 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
3946 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
3947 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
3948 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
3949
3950 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
3951 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
3952 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
3953
3954 };
3955
3956
3957
3958 GRUB_MOD_INIT(ventoy)
3959 {
3960 grub_uint32_t i;
3961 cmd_para *cur = NULL;
3962
3963 ventoy_env_init();
3964
3965 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
3966 {
3967 cur = ventoy_cmds + i;
3968 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
3969 cur->summary, cur->description, cur->parser);
3970 }
3971 }
3972
3973 GRUB_MOD_FINI(ventoy)
3974 {
3975 grub_uint32_t i;
3976
3977 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
3978 {
3979 grub_unregister_extcmd(ventoy_cmds[i].cmd);
3980 }
3981 }
3982