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