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