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