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