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