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