]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
97f4ee1682caad9bbf5bfc2253bc8a5343ab45d0
[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_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3152 {
3153 char buf[32];
3154 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3155
3156 (void)ctxt;
3157
3158 if (argc >= 1)
3159 {
3160 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3161 grub_env_set(args[0], buf);
3162 }
3163
3164 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3165 }
3166
3167 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3168 {
3169 (void)ctxt;
3170 (void)argc;
3171 (void)args;
3172
3173 if (argc == 0)
3174 {
3175 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3176 grub_printf("%s", g_list_script_buf);
3177 }
3178 else
3179 {
3180 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3181 grub_printf("%s", g_tree_script_buf);
3182 }
3183
3184 return 0;
3185 }
3186
3187 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3188 {
3189 img_info *cur = g_ventoy_img_list;
3190
3191 (void)ctxt;
3192 (void)argc;
3193 (void)args;
3194
3195 while (cur)
3196 {
3197 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3198 grub_printf("name:<%s>\n\n", cur->name);
3199 cur = cur->next;
3200 }
3201
3202 return 0;
3203 }
3204
3205 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3206 {
3207 (void)ctxt;
3208 (void)argc;
3209 (void)args;
3210
3211 ventoy_plugin_dump_injection();
3212
3213 return 0;
3214 }
3215
3216 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3217 {
3218 (void)ctxt;
3219 (void)argc;
3220 (void)args;
3221
3222 ventoy_plugin_dump_auto_install();
3223
3224 return 0;
3225 }
3226
3227 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3228 {
3229 (void)ctxt;
3230 (void)argc;
3231 (void)args;
3232
3233 ventoy_plugin_dump_persistence();
3234
3235 return 0;
3236 }
3237
3238 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3239 {
3240 (void)ctxt;
3241 (void)argc;
3242 (void)args;
3243
3244 if (argc != 1)
3245 {
3246 return 1;
3247 }
3248
3249 if (args[0][0] == '0')
3250 {
3251 return g_ventoy_memdisk_mode ? 0 : 1;
3252 }
3253 else if (args[0][0] == '1')
3254 {
3255 return g_ventoy_iso_raw ? 0 : 1;
3256 }
3257 else if (args[0][0] == '2')
3258 {
3259 return g_ventoy_iso_uefi_drv ? 0 : 1;
3260 }
3261 else if (args[0][0] == '3')
3262 {
3263 return g_ventoy_grub2_mode ? 0 : 1;
3264 }
3265 else if (args[0][0] == '4')
3266 {
3267 return g_ventoy_wimboot_mode ? 0 : 1;
3268 }
3269
3270 return 1;
3271 }
3272
3273 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3274 {
3275 static int configfile_mode = 0;
3276 char memfile[128] = {0};
3277
3278 (void)ctxt;
3279 (void)argc;
3280 (void)args;
3281
3282 /*
3283 * args[0]: 0:normal 1:configfile
3284 * args[1]: 0:list_buf 1:tree_buf
3285 */
3286
3287 if (argc != 2)
3288 {
3289 debug("Invalid argc %d\n", argc);
3290 return 0;
3291 }
3292
3293 VTOY_CMD_CHECK(1);
3294
3295 if (args[0][0] == '0')
3296 {
3297 if (args[1][0] == '0')
3298 {
3299 grub_script_execute_sourcecode(g_list_script_buf);
3300 }
3301 else
3302 {
3303 grub_script_execute_sourcecode(g_tree_script_buf);
3304 }
3305 }
3306 else
3307 {
3308 if (configfile_mode)
3309 {
3310 debug("Now already in F3 mode %d\n", configfile_mode);
3311 return 0;
3312 }
3313
3314 if (args[1][0] == '0')
3315 {
3316 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3317 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3318 }
3319 else
3320 {
3321 g_ventoy_last_entry = -1;
3322 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3323 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3324 }
3325
3326 configfile_mode = 1;
3327 grub_script_execute_sourcecode(memfile);
3328 configfile_mode = 0;
3329 }
3330
3331 return 0;
3332 }
3333
3334 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3335 {
3336 grub_file_t file;
3337
3338 (void)ctxt;
3339
3340 if (argc != 1)
3341 {
3342 return 1;
3343 }
3344
3345 g_ventoy_case_insensitive = 1;
3346 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3347 g_ventoy_case_insensitive = 0;
3348
3349 grub_errno = 0;
3350
3351 if (file)
3352 {
3353 grub_file_close(file);
3354 return 0;
3355 }
3356 return 1;
3357 }
3358
3359 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3360 {
3361 int id = 0;
3362 int find = 0;
3363 grub_disk_t disk;
3364 const char *isopath = NULL;
3365 char hdname[32];
3366 ventoy_mbr_head mbr;
3367
3368 (void)ctxt;
3369 (void)argc;
3370
3371 if (argc != 1)
3372 {
3373 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3374 }
3375
3376 isopath = grub_env_get("vtoy_iso_part");
3377 if (!isopath)
3378 {
3379 debug("isopath is null %p\n", isopath);
3380 return 0;
3381 }
3382
3383 debug("isopath is %s\n", isopath);
3384
3385 for (id = 0; id < 30 && (find == 0); id++)
3386 {
3387 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3388 if (grub_strstr(isopath, hdname))
3389 {
3390 debug("skip %s ...\n", hdname);
3391 continue;
3392 }
3393
3394 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3395
3396 disk = grub_disk_open(hdname);
3397 if (!disk)
3398 {
3399 debug("%s not exist\n", hdname);
3400 break;
3401 }
3402
3403 grub_memset(&mbr, 0, sizeof(mbr));
3404 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3405 {
3406 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3407 {
3408 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3409 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3410 {
3411
3412 grub_env_set(args[0], hdname);
3413 find = 1;
3414 }
3415 }
3416 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3417 }
3418 else
3419 {
3420 debug("read %s failed\n", hdname);
3421 }
3422
3423 grub_disk_close(disk);
3424 }
3425
3426 return 0;
3427 }
3428
3429 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3430 {
3431 int len = 1024;
3432 grub_file_t file;
3433 char *buf = NULL;
3434
3435 (void)ctxt;
3436 (void)argc;
3437
3438 if (argc != 2)
3439 {
3440 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3441 }
3442
3443 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3444 if (!file)
3445 {
3446 debug("failed to open file %s\n", args[0]);
3447 return 0;
3448 }
3449
3450 buf = grub_malloc(len);
3451 if (!buf)
3452 {
3453 goto end;
3454 }
3455
3456 buf[len - 1] = 0;
3457 grub_file_read(file, buf, len - 1);
3458
3459 ventoy_get_line(buf);
3460 ventoy_set_env(args[1], buf);
3461
3462 end:
3463
3464 grub_check_free(buf);
3465 grub_file_close(file);
3466
3467 return 0;
3468 }
3469
3470 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3471 {
3472 (void)disk;
3473 (void)data;
3474
3475 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3476 "0 %llu linear /dev/ventoy %llu\n",
3477 (ulonglong)partition->len, (ulonglong)partition->start);
3478
3479 return 0;
3480 }
3481
3482 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3483 {
3484 char *device_name = NULL;
3485 grub_device_t dev = NULL;
3486 char buf[64];
3487
3488 (void)ctxt;
3489
3490 g_part_list_pos = 0;
3491 grub_env_unset("vtoy_img_part_file");
3492
3493 if (argc != 1)
3494 {
3495 return 1;
3496 }
3497
3498 device_name = grub_file_get_device_name(args[0]);
3499 if (!device_name)
3500 {
3501 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3502 goto end;
3503 }
3504
3505 dev = grub_device_open(device_name);
3506 if (!dev)
3507 {
3508 debug("grub_device_open failed, %s\n", device_name);
3509 goto end;
3510 }
3511
3512 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, NULL);
3513
3514 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3515 grub_env_set("vtoy_img_part_file", buf);
3516
3517 end:
3518
3519 check_free(device_name, grub_free);
3520 check_free(dev, grub_device_close);
3521
3522 return 0;
3523 }
3524
3525
3526 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3527 {
3528 int rc = 1;
3529 grub_file_t file;
3530 char *buf = NULL;
3531
3532 (void)ctxt;
3533 (void)argc;
3534
3535 if (argc != 2)
3536 {
3537 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3538 }
3539
3540 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3541 if (!file)
3542 {
3543 debug("failed to open file %s\n", args[0]);
3544 return 1;
3545 }
3546
3547 buf = grub_malloc(file->size + 1);
3548 if (!buf)
3549 {
3550 goto end;
3551 }
3552
3553 buf[file->size] = 0;
3554 grub_file_read(file, buf, file->size);
3555
3556 if (grub_strstr(buf, args[1]))
3557 {
3558 rc = 0;
3559 }
3560
3561 end:
3562
3563 grub_check_free(buf);
3564 grub_file_close(file);
3565
3566 return rc;
3567 }
3568
3569 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3570 {
3571 int len;
3572 grub_file_t file;
3573 char buf[64];
3574 grub_uint64_t size;
3575 ventoy_iso9660_vd pvd;
3576
3577 (void)ctxt;
3578 (void)argc;
3579
3580 if (argc != 4)
3581 {
3582 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3583 }
3584
3585 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3586 if (!file)
3587 {
3588 debug("failed to open file %s\n", args[0]);
3589 return 0;
3590 }
3591
3592 grub_file_seek(file, 16 * 2048);
3593 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3594 if (len != sizeof(pvd))
3595 {
3596 debug("failed to read pvd %d\n", len);
3597 goto end;
3598 }
3599
3600 grub_memset(buf, 0, sizeof(buf));
3601 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3602 ventoy_set_env(args[1], buf);
3603
3604 grub_memset(buf, 0, sizeof(buf));
3605 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3606 ventoy_set_env(args[2], buf);
3607
3608 size = pvd.space;
3609 size *= 2048;
3610 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3611 ventoy_set_env(args[3], buf);
3612
3613 end:
3614 grub_file_close(file);
3615
3616 return 0;
3617 }
3618
3619 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3620 {
3621 int len;
3622 grub_file_t file;
3623 char buf[64];
3624
3625 (void)ctxt;
3626 (void)argc;
3627
3628 if (argc != 2)
3629 {
3630 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3631 }
3632
3633 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3634 if (!file)
3635 {
3636 debug("failed to open file %s\n", args[0]);
3637 return 0;
3638 }
3639
3640 grub_memset(buf, 0, sizeof(buf));
3641 grub_file_seek(file, 16 * 2048 + 813);
3642 len = (int)grub_file_read(file, buf, 17);
3643 if (len != 17)
3644 {
3645 debug("failed to read create date %d\n", len);
3646 goto end;
3647 }
3648
3649 ventoy_set_env(args[1], buf);
3650
3651 end:
3652 grub_file_close(file);
3653
3654 return 0;
3655 }
3656
3657 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3658 {
3659 (void)ctxt;
3660 (void)argc;
3661 (void)args;
3662
3663 ventoy_env_hook_root(1);
3664
3665 return 0;
3666 }
3667
3668 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3669 {
3670 (void)ctxt;
3671 (void)argc;
3672 (void)args;
3673
3674 ventoy_env_hook_root(0);
3675
3676 return 0;
3677 }
3678
3679 #ifdef GRUB_MACHINE_EFI
3680 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3681 {
3682 int ret = 1;
3683 grub_uint8_t *var;
3684 grub_size_t size;
3685 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3686
3687 (void)ctxt;
3688 (void)argc;
3689 (void)args;
3690
3691 var = grub_efi_get_variable("SecureBoot", &global, &size);
3692 if (var && *var == 1)
3693 {
3694 return 0;
3695 }
3696
3697 return ret;
3698 }
3699 #else
3700 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3701 {
3702 (void)ctxt;
3703 (void)argc;
3704 (void)args;
3705 return 1;
3706 }
3707 #endif
3708
3709 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3710 {
3711 int i;
3712 int ret = 1;
3713 grub_file_t file;
3714 grub_uint64_t FileSectors = 0;
3715 ventoy_gpt_info *gpt = NULL;
3716 ventoy_part_table *pt = NULL;
3717 grub_uint8_t zeroguid[16] = {0};
3718
3719 (void)ctxt;
3720 (void)argc;
3721
3722 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3723 if (!file)
3724 {
3725 debug("failed to open file %s\n", args[0]);
3726 return 1;
3727 }
3728
3729 if (file->size % 512)
3730 {
3731 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3732 goto out;
3733 }
3734
3735 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3736 if (!gpt)
3737 {
3738 goto out;
3739 }
3740
3741 FileSectors = file->size / 512;
3742
3743 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3744 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3745 {
3746 debug("This is EFI partition table\n");
3747
3748 for (i = 0; i < 128; i++)
3749 {
3750 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3751 {
3752 if (FileSectors < gpt->PartTbl[i].LastLBA)
3753 {
3754 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3755 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3756 goto out;
3757 }
3758 }
3759 }
3760 }
3761 else
3762 {
3763 debug("This is MBR partition table\n");
3764
3765 for (i = 0; i < 4; i++)
3766 {
3767 pt = gpt->MBR.PartTbl + i;
3768 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3769 {
3770 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3771 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3772 (ulonglong)FileSectors);
3773 goto out;
3774 }
3775 }
3776 }
3777
3778 ret = 0;
3779
3780 out:
3781 grub_file_close(file);
3782 grub_check_free(gpt);
3783 grub_errno = GRUB_ERR_NONE;
3784 return ret;
3785 }
3786
3787 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3788 {
3789 int i;
3790 int ret;
3791
3792 (void)ctxt;
3793 (void)argc;
3794 (void)args;
3795
3796 for (i = 0; i < 500; i++)
3797 {
3798 ret = grub_getkey_noblock();
3799 if (ret == GRUB_TERM_NO_KEY)
3800 {
3801 break;
3802 }
3803 }
3804
3805 if (i >= 500)
3806 {
3807 grub_cls();
3808 grub_printf("\n\n Still have key input after clear.\n");
3809 grub_refresh();
3810 grub_sleep(5);
3811 }
3812
3813 return 0;
3814 }
3815
3816 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3817 {
3818 int i;
3819 int buflen;
3820 int datalen;
3821 int loclen;
3822 int img_chunk_num;
3823 int image_sector_size;
3824 char cmd[64];
3825 ventoy_chain_head *chain;
3826 ventoy_img_chunk *chunk;
3827 ventoy_os_param *osparam;
3828 ventoy_image_location *location;
3829 ventoy_image_disk_region *region;
3830 struct grub_acpi_table_header *acpi;
3831
3832 (void)ctxt;
3833
3834 if (argc != 2)
3835 {
3836 return 1;
3837 }
3838
3839 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3840
3841 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3842 if (!chain)
3843 {
3844 return 1;
3845 }
3846
3847 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3848
3849 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3850 {
3851 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3852 return 1;
3853 }
3854
3855 img_chunk_num = chain->img_chunk_num;
3856
3857 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3858 datalen = sizeof(ventoy_os_param) + loclen;
3859
3860 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3861 acpi = grub_zalloc(buflen);
3862 if (!acpi)
3863 {
3864 return 1;
3865 }
3866
3867 /* Step1: Fill acpi table header */
3868 grub_memcpy(acpi->signature, "VTOY", 4);
3869 acpi->length = buflen;
3870 acpi->revision = 1;
3871 grub_memcpy(acpi->oemid, "VENTOY", 6);
3872 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
3873 acpi->oemrev = 1;
3874 acpi->creator_id[0] = 1;
3875 acpi->creator_rev = 1;
3876
3877 /* Step2: Fill data */
3878 osparam = (ventoy_os_param *)(acpi + 1);
3879 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
3880 osparam->vtoy_img_location_addr = 0;
3881 osparam->vtoy_img_location_len = loclen;
3882 osparam->chksum = 0;
3883 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
3884
3885 location = (ventoy_image_location *)(osparam + 1);
3886 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
3887 location->image_sector_size = image_sector_size;
3888 location->disk_sector_size = chain->disk_sector_size;
3889 location->region_count = img_chunk_num;
3890
3891 region = location->regions;
3892 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
3893 if (512 == image_sector_size)
3894 {
3895 for (i = 0; i < img_chunk_num; i++)
3896 {
3897 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
3898 region->image_start_sector = chunk->img_start_sector * 4;
3899 region->disk_start_sector = chunk->disk_start_sector;
3900 region++;
3901 chunk++;
3902 }
3903 }
3904 else
3905 {
3906 for (i = 0; i < img_chunk_num; i++)
3907 {
3908 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
3909 region->image_start_sector = chunk->img_start_sector;
3910 region->disk_start_sector = chunk->disk_start_sector;
3911 region++;
3912 chunk++;
3913 }
3914 }
3915
3916 /* Step3: Fill acpi checksum */
3917 acpi->checksum = 0;
3918 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
3919
3920 /* load acpi table */
3921 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
3922 grub_script_execute_sourcecode(cmd);
3923
3924 grub_free(acpi);
3925
3926 VENTOY_CMD_RETURN(0);
3927 }
3928
3929 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3930 {
3931 (void)ctxt;
3932 (void)argc;
3933 (void)args;
3934
3935 g_ventoy_last_entry_back = g_ventoy_last_entry;
3936 g_ventoy_last_entry = -1;
3937
3938 return 0;
3939 }
3940
3941 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
3942 {
3943 (void)ctxt;
3944 (void)argc;
3945 (void)args;
3946
3947 g_ventoy_last_entry = g_ventoy_last_entry_back;
3948
3949 return 0;
3950 }
3951
3952 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
3953 {
3954 const char *pos = filename + 1;
3955
3956 if (info->dir)
3957 {
3958 while (*pos)
3959 {
3960 if (*pos == '.')
3961 {
3962 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
3963 {
3964 grub_strncpy((char *)data, filename, 128);
3965 return 1;
3966 }
3967 }
3968 pos++;
3969 }
3970 }
3971
3972 return 0;
3973 }
3974
3975 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
3976 {
3977 int rc = 1;
3978 char *device_name = NULL;
3979 grub_device_t dev = NULL;
3980 grub_fs_t fs = NULL;
3981 char buf[128] = {0};
3982
3983 (void)ctxt;
3984
3985 if (argc != 3)
3986 {
3987 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
3988 return 1;
3989 }
3990
3991 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
3992
3993 device_name = grub_file_get_device_name(args[0]);
3994 if (!device_name)
3995 {
3996 debug("grub_file_get_device_name failed, %s\n", args[0]);
3997 goto end;
3998 }
3999
4000 dev = grub_device_open(device_name);
4001 if (!dev)
4002 {
4003 debug("grub_device_open failed, %s\n", device_name);
4004 goto end;
4005 }
4006
4007 fs = grub_fs_probe(dev);
4008 if (!fs)
4009 {
4010 debug("grub_fs_probe failed, %s\n", device_name);
4011 goto end;
4012 }
4013
4014 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4015
4016 if (buf[0])
4017 {
4018 ventoy_set_env(args[2], buf);
4019 }
4020
4021 rc = 0;
4022
4023 end:
4024
4025 check_free(device_name, grub_free);
4026 check_free(dev, grub_device_close);
4027
4028 return rc;
4029 }
4030
4031 int ventoy_load_part_table(const char *diskname)
4032 {
4033 char name[64];
4034 int ret;
4035 grub_disk_t disk;
4036 grub_device_t dev;
4037
4038 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4039 if (!g_ventoy_part_info)
4040 {
4041 return 1;
4042 }
4043
4044 disk = grub_disk_open(diskname);
4045 if (!disk)
4046 {
4047 debug("Failed to open disk %s\n", diskname);
4048 return 1;
4049 }
4050
4051 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4052
4053 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4054 grub_disk_close(disk);
4055
4056 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4057 dev = grub_device_open(name);
4058 if (dev)
4059 {
4060 /* Check for official Ventoy device */
4061 ret = ventoy_check_official_device(dev);
4062 grub_device_close(dev);
4063
4064 if (ret)
4065 {
4066 return 1;
4067 }
4068 }
4069
4070 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4071 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4072
4073 return 0;
4074 }
4075
4076 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4077 {
4078 int ret;
4079
4080 (void)argc;
4081 (void)ctxt;
4082
4083 ret = ventoy_load_part_table(args[0]);
4084 if (ret)
4085 {
4086 grub_exit();
4087 }
4088
4089 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4090 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4091
4092 return 0;
4093 }
4094
4095 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4096 {
4097 int ret = 1;
4098 const char *vcfg = NULL;
4099
4100 (void)argc;
4101 (void)ctxt;
4102
4103 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4104 if (vcfg)
4105 {
4106 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4107 grub_env_set(args[1], vcfg);
4108 ret = 0;
4109 }
4110 else
4111 {
4112 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4113 }
4114
4115 grub_errno = 0;
4116 return ret;
4117 }
4118
4119
4120 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4121 {
4122 int id;
4123 grub_uint8_t zeroguid[16] = {0};
4124
4125 (void)argc;
4126 (void)ctxt;
4127
4128 id = (int)grub_strtoul(args[0], NULL, 10);
4129 grub_errno = 0;
4130
4131 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4132 {
4133 if (id >= 1 && id <= 128)
4134 {
4135 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4136 {
4137 return 0;
4138 }
4139 }
4140 }
4141 else
4142 {
4143 if (id >= 1 && id <= 4)
4144 {
4145 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4146 {
4147 return 0;
4148 }
4149 }
4150 }
4151
4152 return 1;
4153 }
4154
4155 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4156 {
4157 int rc = 1;
4158 char *device_name = NULL;
4159 grub_device_t dev = NULL;
4160 grub_fs_t fs = NULL;
4161 char *label = NULL;
4162
4163 (void)ctxt;
4164
4165 debug("get fs label for %s\n", args[0]);
4166
4167 if (argc != 2)
4168 {
4169 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4170 return 1;
4171 }
4172
4173 device_name = grub_file_get_device_name(args[0]);
4174 if (!device_name)
4175 {
4176 debug("grub_file_get_device_name failed, %s\n", args[0]);
4177 goto end;
4178 }
4179
4180 dev = grub_device_open(device_name);
4181 if (!dev)
4182 {
4183 debug("grub_device_open failed, %s\n", device_name);
4184 goto end;
4185 }
4186
4187 fs = grub_fs_probe(dev);
4188 if (NULL == fs || NULL == fs->fs_label)
4189 {
4190 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4191 goto end;
4192 }
4193
4194 fs->fs_label(dev, &label);
4195 if (label)
4196 {
4197 debug("label=<%s>\n", label);
4198 ventoy_set_env(args[1], label);
4199 grub_free(label);
4200 }
4201
4202 rc = 0;
4203
4204 end:
4205
4206 check_free(device_name, grub_free);
4207 check_free(dev, grub_device_close);
4208
4209 return rc;
4210 }
4211
4212 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4213 {
4214 if (!info->dir)
4215 {
4216 grub_snprintf((char *)data, 256, "%s", filename);
4217 return 1;
4218 }
4219
4220 return 0;
4221 }
4222
4223 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4224 {
4225 if (info->dir && filename && filename[0] != '.')
4226 {
4227 grub_snprintf((char *)data, 256, "%s", filename);
4228 return 1;
4229 }
4230
4231 return 0;
4232 }
4233
4234 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4235 {
4236 int rc = 1;
4237 char *device_name = NULL;
4238 grub_device_t dev = NULL;
4239 grub_fs_t fs = NULL;
4240 char name[256] ={0};
4241
4242 if (argc != 3)
4243 {
4244 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4245 return 1;
4246 }
4247
4248 device_name = grub_file_get_device_name(args[0]);
4249 if (!device_name)
4250 {
4251 debug("grub_file_get_device_name failed, %s\n", args[0]);
4252 goto end;
4253 }
4254
4255 dev = grub_device_open(device_name);
4256 if (!dev)
4257 {
4258 debug("grub_device_open failed, %s\n", device_name);
4259 goto end;
4260 }
4261
4262 fs = grub_fs_probe(dev);
4263 if (!fs)
4264 {
4265 debug("grub_fs_probe failed, %s\n", device_name);
4266 goto end;
4267 }
4268
4269 fs->fs_dir(dev, args[1], hook, name);
4270 if (name[0])
4271 {
4272 ventoy_set_env(args[2], name);
4273 }
4274
4275 rc = 0;
4276
4277 end:
4278
4279 check_free(device_name, grub_free);
4280 check_free(dev, grub_device_close);
4281
4282 return rc;
4283 }
4284
4285 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4286 {
4287 (void)ctxt;
4288 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4289 }
4290
4291 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4292 {
4293 (void)ctxt;
4294 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4295 }
4296
4297 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4298 {
4299 char c;
4300 char *pos = NULL;
4301 char *end = NULL;
4302
4303 (void)ctxt;
4304
4305 if (argc != 2)
4306 {
4307 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4308 return 1;
4309 }
4310
4311 for (pos = args[0]; *pos; pos++)
4312 {
4313 if (*pos == '.')
4314 {
4315 end = pos;
4316 }
4317 }
4318
4319 if (end)
4320 {
4321 c = *end;
4322 *end = 0;
4323 }
4324
4325 grub_env_set(args[1], args[0]);
4326
4327 if (end)
4328 {
4329 *end = c;
4330 }
4331
4332 return 0;
4333 }
4334
4335 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4336 {
4337 int i;
4338 int len;
4339 const char *buf;
4340
4341 (void)ctxt;
4342
4343 if (argc != 2)
4344 {
4345 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4346 return 1;
4347 }
4348
4349 buf = args[0];
4350 len = (int)grub_strlen(buf);
4351 for (i = len; i > 0; i--)
4352 {
4353 if (buf[i - 1] == '/')
4354 {
4355 grub_env_set(args[1], buf + i);
4356 return 0;
4357 }
4358 }
4359
4360 grub_env_set(args[1], buf);
4361
4362 return 0;
4363 }
4364
4365 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4366 {
4367 struct grub_video_mode_info info;
4368 char buf[32];
4369
4370 (void)ctxt;
4371 (void)argc;
4372 (void)args;
4373
4374 if (!g_video_mode_list)
4375 {
4376 ventoy_enum_video_mode();
4377 }
4378
4379 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4380 {
4381 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4382 }
4383 else
4384 {
4385 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4386 }
4387
4388 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4389
4390 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4391 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4392
4393 VENTOY_CMD_RETURN(0);
4394 }
4395
4396 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4397 {
4398 struct grub_video_mode_info info;
4399 char buf[32];
4400
4401 (void)ctxt;
4402 (void)argc;
4403 (void)args;
4404
4405 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4406 {
4407 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4408 }
4409 else
4410 {
4411 grub_snprintf(buf, sizeof(buf), "0x0x0");
4412 }
4413
4414 grub_env_set(args[0], buf);
4415
4416 VENTOY_CMD_RETURN(0);
4417 }
4418
4419 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4420 {
4421 int id;
4422 char buf[32];
4423
4424 (void)ctxt;
4425 (void)argc;
4426
4427 if (!g_video_mode_list)
4428 {
4429 return 0;
4430 }
4431
4432 id = (int)grub_strtoul(args[0], NULL, 10);
4433 if (id < g_video_mode_num)
4434 {
4435 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4436 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4437 }
4438
4439 grub_env_set(args[1], buf);
4440
4441 VENTOY_CMD_RETURN(0);
4442 }
4443
4444 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4445 {
4446 grub_uint32_t i;
4447 grub_uint32_t loadsector = 0;
4448 grub_file_t file;
4449 char value[32];
4450 grub_uint32_t boot_catlog = 0;
4451 grub_uint8_t buf[512];
4452
4453 (void)ctxt;
4454
4455 if (argc != 2)
4456 {
4457 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4458 return 1;
4459 }
4460
4461 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4462 if (!file)
4463 {
4464 debug("failed to open %s\n", args[0]);
4465 return 1;
4466 }
4467
4468 boot_catlog = ventoy_get_iso_boot_catlog(file);
4469 if (boot_catlog == 0)
4470 {
4471 debug("No bootcatlog found\n");
4472 grub_file_close(file);
4473 return 1;
4474 }
4475
4476 grub_memset(buf, 0, sizeof(buf));
4477 grub_file_seek(file, boot_catlog * 2048);
4478 grub_file_read(file, buf, sizeof(buf));
4479 grub_file_close(file);
4480
4481 for (i = 0; i < sizeof(buf); i += 32)
4482 {
4483 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4484 {
4485 if (buf[i + 32] == 0x88)
4486 {
4487 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4488 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4489 break;
4490 }
4491 }
4492 }
4493
4494 if (loadsector == 0)
4495 {
4496 debug("No EFI eltorito info found\n");
4497 return 1;
4498 }
4499
4500 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4501 grub_env_set(args[1], value);
4502 VENTOY_CMD_RETURN(0);
4503 }
4504
4505 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4506 {
4507 int curpos;
4508 int printlen;
4509 grub_size_t len;
4510 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4511
4512 if (pfsdir->initrd[0])
4513 {
4514 return 1;
4515 }
4516
4517 curpos = pfsdir->curpos;
4518 len = grub_strlen(filename);
4519
4520 if (info->dir)
4521 {
4522 if ((len == 1 && filename[0] == '.') ||
4523 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4524 {
4525 return 0;
4526 }
4527
4528 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4529 pfsdir->dircnt++;
4530
4531 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4532 pfsdir->curpos = curpos + printlen;
4533 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4534 pfsdir->curpos = curpos;
4535 pfsdir->fullpath[curpos] = 0;
4536 }
4537 else
4538 {
4539 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4540 pfsdir->filecnt++;
4541
4542 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4543 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4544 {
4545 if (info->size > 32 * VTOY_SIZE_1MB)
4546 {
4547 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4548 return 1;
4549 }
4550 }
4551 }
4552
4553 return 0;
4554 }
4555
4556 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4557 {
4558 int i;
4559 char *pos = NULL;
4560 char *device_name = NULL;
4561 grub_device_t dev = NULL;
4562 grub_fs_t fs = NULL;
4563 replace_fs_dir *pfsdir = NULL;
4564
4565 (void)ctxt;
4566
4567 if (argc != 2)
4568 {
4569 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4570 return 1;
4571 }
4572
4573 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4574 if (!pfsdir)
4575 {
4576 return 1;
4577 }
4578
4579 device_name = grub_file_get_device_name(args[0]);
4580 if (!device_name)
4581 {
4582 goto fail;
4583 }
4584
4585 dev = grub_device_open(device_name);
4586 if (!dev)
4587 {
4588 goto fail;
4589 }
4590
4591 fs = grub_fs_probe(dev);
4592 if (!fs)
4593 {
4594 goto fail;
4595 }
4596
4597 pfsdir->dev = dev;
4598 pfsdir->fs = fs;
4599 pfsdir->curpos = 1;
4600 pfsdir->fullpath[0] = '/';
4601 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4602
4603 if (pfsdir->initrd[0])
4604 {
4605 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4606
4607 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4608 {
4609 if (pfsdir->initrd[i] == '/')
4610 {
4611 pfsdir->initrd[i] = '\\';
4612 }
4613 }
4614
4615 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4616 grub_env_set(args[1], pos);
4617 }
4618 else
4619 {
4620 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4621 }
4622
4623 fail:
4624
4625 grub_check_free(pfsdir);
4626 grub_check_free(device_name);
4627 check_free(dev, grub_device_close);
4628
4629 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4630 }
4631
4632 int ventoy_env_init(void)
4633 {
4634 char buf[64];
4635
4636 grub_env_set("vtdebug_flag", "");
4637
4638 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4639 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4640 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4641 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4642
4643 ventoy_filt_register(0, ventoy_wrapper_open);
4644
4645 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4646 if (g_grub_param)
4647 {
4648 g_grub_param->grub_env_get = grub_env_get;
4649 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
4650 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
4651 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
4652 grub_env_set("env_param", buf);
4653 grub_env_set("ventoy_env_param", buf);
4654
4655 grub_env_export("env_param");
4656 grub_env_export("ventoy_env_param");
4657 }
4658
4659 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
4660 grub_env_set("vtoy_winpeshl_ini_addr", buf);
4661
4662 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
4663 grub_env_set("vtoy_winpeshl_ini_size", buf);
4664
4665 grub_env_export("vtoy_winpeshl_ini_addr");
4666 grub_env_export("vtoy_winpeshl_ini_size");
4667
4668 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
4669 grub_env_set("vtoy_chain_file_size", buf);
4670 grub_env_export("vtoy_chain_file_size");
4671
4672 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
4673 grub_env_set("vtoy_chain_file_read", buf);
4674 grub_env_export("vtoy_chain_file_read");
4675
4676 return 0;
4677 }
4678
4679 static cmd_para ventoy_cmds[] =
4680 {
4681 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
4682 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
4683 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
4684 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
4685 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4686 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
4687 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
4688 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
4689 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
4690 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
4691 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
4692 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
4693 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
4694 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
4695 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
4696 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
4697 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
4698 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
4699 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
4700 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
4701 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
4702 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
4703 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
4704 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
4705
4706 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
4707 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
4708 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
4709 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
4710 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
4711 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
4712 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
4713
4714 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
4715 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
4716 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
4717 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
4718 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
4719 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
4720 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
4721 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
4722 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
4723 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
4724
4725
4726 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
4727 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
4728 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
4729 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
4730 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
4731 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
4732 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
4733 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
4734 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
4735 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
4736 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
4737
4738 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
4739 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
4740 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
4741 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
4742 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
4743 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
4744
4745 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4746 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
4747 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
4748 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
4749 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
4750 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
4751 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
4752 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
4753 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
4754 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
4755
4756 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
4757 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
4758 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
4759 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
4760 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
4761 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
4762 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
4763 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
4764 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
4765
4766 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
4767 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
4768 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
4769 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
4770
4771
4772 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
4773 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
4774 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
4775
4776 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
4777 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
4778 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
4779
4780
4781 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
4782 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
4783 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
4784 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
4785 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
4786 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
4787 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
4788 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
4789 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
4790 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
4791 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
4792
4793 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
4794 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
4795 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
4796 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
4797 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
4798 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
4799 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
4800 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
4801 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
4802 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
4803
4804 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
4805 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
4806 };
4807
4808 int ventoy_register_all_cmd(void)
4809 {
4810 grub_uint32_t i;
4811 cmd_para *cur = NULL;
4812
4813 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4814 {
4815 cur = ventoy_cmds + i;
4816 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
4817 cur->summary, cur->description, cur->parser);
4818 }
4819
4820 return 0;
4821 }
4822
4823 int ventoy_unregister_all_cmd(void)
4824 {
4825 grub_uint32_t i;
4826
4827 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
4828 {
4829 grub_unregister_extcmd(ventoy_cmds[i].cmd);
4830 }
4831
4832 return 0;
4833 }
4834
4835