]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
fc1279fcf6a8f7199c63e73dcd2c7437c17e5fab
[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/random.h>
49 #include <grub/ventoy.h>
50 #include "ventoy_def.h"
51 #include "miniz.h"
52
53 GRUB_MOD_LICENSE ("GPLv3+");
54
55 static grub_uint8_t g_check_mbr_data[] = {
56 0xEB, 0x63, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44, 0x00, 0x52, 0x64, 0x00, 0x20, 0x45, 0x72, 0x0D,
60 };
61
62 initrd_info *g_initrd_img_list = NULL;
63 initrd_info *g_initrd_img_tail = NULL;
64 int g_initrd_img_count = 0;
65 int g_valid_initrd_count = 0;
66 int g_default_menu_mode = 0;
67 int g_filt_dot_underscore_file = 0;
68 int g_sort_case_sensitive = 0;
69 int g_tree_view_menu_style = 0;
70 static grub_file_t g_old_file;
71 static int g_ventoy_last_entry_back;
72
73 char g_iso_path[256];
74 char g_img_swap_tmp_buf[1024];
75 img_info g_img_swap_tmp;
76 img_info *g_ventoy_img_list = NULL;
77
78 int g_ventoy_img_count = 0;
79
80 grub_device_t g_enum_dev = NULL;
81 grub_fs_t g_enum_fs = NULL;
82 int g_img_max_search_level = -1;
83 img_iterator_node g_img_iterator_head;
84 img_iterator_node *g_img_iterator_tail = NULL;
85
86 grub_uint8_t g_ventoy_break_level = 0;
87 grub_uint8_t g_ventoy_debug_level = 0;
88 grub_uint8_t g_ventoy_chain_type = 0;
89
90 grub_uint8_t *g_ventoy_cpio_buf = NULL;
91 grub_uint32_t g_ventoy_cpio_size = 0;
92 cpio_newc_header *g_ventoy_initrd_head = NULL;
93 grub_uint8_t *g_ventoy_runtime_buf = NULL;
94
95 int g_plugin_image_list = 0;
96
97 ventoy_grub_param *g_grub_param = NULL;
98
99 ventoy_guid g_ventoy_guid = VENTOY_GUID;
100
101 ventoy_img_chunk_list g_img_chunk_list;
102
103 int g_wimboot_enable = 0;
104 ventoy_img_chunk_list g_wimiso_chunk_list;
105 char *g_wimiso_path = NULL;
106 grub_uint32_t g_wimiso_size = 0;
107
108 int g_vhdboot_enable = 0;
109
110 grub_uint64_t g_svd_replace_offset = 0;
111
112 int g_conf_replace_count = 0;
113 grub_uint64_t g_conf_replace_offset[VTOY_MAX_CONF_REPLACE] = { 0 };
114 conf_replace *g_conf_replace_node[VTOY_MAX_CONF_REPLACE] = { NULL };
115 grub_uint8_t *g_conf_replace_new_buf[VTOY_MAX_CONF_REPLACE] = { NULL };
116 int g_conf_replace_new_len[VTOY_MAX_CONF_REPLACE] = { 0 };
117 int g_conf_replace_new_len_align[VTOY_MAX_CONF_REPLACE] = { 0 };
118
119 int g_ventoy_disk_bios_id = 0;
120 ventoy_gpt_info *g_ventoy_part_info = NULL;
121 grub_uint64_t g_ventoy_disk_size = 0;
122 grub_uint64_t g_ventoy_disk_part_size[2];
123
124 char *g_tree_script_buf = NULL;
125 int g_tree_script_pos = 0;
126 int g_tree_script_pre = 0;
127
128 static char *g_list_script_buf = NULL;
129 static int g_list_script_pos = 0;
130
131 static char *g_part_list_buf = NULL;
132 static int g_part_list_pos = 0;
133 static grub_uint64_t g_part_end_max = 0;
134
135 static int g_video_mode_max = 0;
136 static int g_video_mode_num = 0;
137 static ventoy_video_mode *g_video_mode_list = NULL;
138
139 static int g_enumerate_time_checked = 0;
140 static grub_uint64_t g_enumerate_start_time_ms;
141 static grub_uint64_t g_enumerate_finish_time_ms;
142 int g_vtoy_file_flt[VTOY_FILE_FLT_BUTT] = {0};
143
144 static char g_iso_vd_id_publisher[130];
145 static char g_iso_vd_id_prepare[130];
146 static char g_iso_vd_id_application[130];
147
148 static int g_pager_flag = 0;
149 static char g_old_pager[32];
150
151 static const char *g_vtoy_winpeshl_ini = "[LaunchApps]\r\nvtoyjump.exe";
152
153 const char *g_menu_class[img_type_max] =
154 {
155 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
156 };
157
158 const char *g_menu_prefix[img_type_max] =
159 {
160 "iso", "wim", "efi", "img", "vhd", "vtoy"
161 };
162
163 static int g_vtoy_load_prompt = 0;
164 static char g_vtoy_prompt_msg[64];
165
166 static char g_json_case_mis_path[32];
167
168 static ventoy_vlnk_part *g_vlnk_part_list = NULL;
169
170 int ventoy_get_fs_type(const char *fs)
171 {
172 if (NULL == fs)
173 {
174 return ventoy_fs_max;
175 }
176 else if (grub_strncmp(fs, "exfat", 5) == 0)
177 {
178 return ventoy_fs_exfat;
179 }
180 else if (grub_strncmp(fs, "ntfs", 4) == 0)
181 {
182 return ventoy_fs_ntfs;
183 }
184 else if (grub_strncmp(fs, "ext", 3) == 0)
185 {
186 return ventoy_fs_ext;
187 }
188 else if (grub_strncmp(fs, "xfs", 3) == 0)
189 {
190 return ventoy_fs_xfs;
191 }
192 else if (grub_strncmp(fs, "udf", 3) == 0)
193 {
194 return ventoy_fs_udf;
195 }
196 else if (grub_strncmp(fs, "fat", 3) == 0)
197 {
198 return ventoy_fs_fat;
199 }
200
201 return ventoy_fs_max;
202 }
203
204 static int ventoy_string_check(const char *str, grub_char_check_func check)
205 {
206 if (!str)
207 {
208 return 0;
209 }
210
211 for ( ; *str; str++)
212 {
213 if (!check(*str))
214 {
215 return 0;
216 }
217 }
218
219 return 1;
220 }
221
222
223 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
224 {
225 grub_memcpy(buf, (char *)file->data + file->offset, len);
226 return len;
227 }
228
229 static int ventoy_control_get_flag(const char *key)
230 {
231 const char *val = ventoy_get_env(key);
232
233 if (val && val[0] == '1' && val[1] == 0)
234 {
235 return 1;
236 }
237 return 0;
238 }
239
240 static grub_err_t ventoy_fs_close(grub_file_t file)
241 {
242 grub_file_close(g_old_file);
243 grub_free(file->data);
244
245 file->device = 0;
246 file->name = 0;
247
248 return 0;
249 }
250
251 static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg)
252 {
253 int i;
254
255 (void)hook_arg;
256
257 if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
258 {
259 return 0;
260 }
261
262 for (i = 0; i < g_video_mode_num; i++)
263 {
264 if (g_video_mode_list[i].width == info->width &&
265 g_video_mode_list[i].height == info->height &&
266 g_video_mode_list[i].bpp == info->bpp)
267 {
268 return 0;
269 }
270 }
271
272 g_video_mode_list[g_video_mode_num].width = info->width;
273 g_video_mode_list[g_video_mode_num].height = info->height;
274 g_video_mode_list[g_video_mode_num].bpp = info->bpp;
275 g_video_mode_num++;
276
277 if (g_video_mode_num == g_video_mode_max)
278 {
279 g_video_mode_max *= 2;
280 g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode));
281 }
282
283 return 0;
284 }
285
286 static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2)
287 {
288 if (v1->bpp == v2->bpp)
289 {
290 if (v1->width == v2->width)
291 {
292 if (v1->height == v2->height)
293 {
294 return 0;
295 }
296 else
297 {
298 return (v1->height < v2->height) ? -1 : 1;
299 }
300 }
301 else
302 {
303 return (v1->width < v2->width) ? -1 : 1;
304 }
305 }
306 else
307 {
308 return (v1->bpp < v2->bpp) ? -1 : 1;
309 }
310 }
311
312 static int ventoy_enum_video_mode(void)
313 {
314 int i, j;
315 grub_video_adapter_t adapter;
316 grub_video_driver_id_t id;
317 ventoy_video_mode mode;
318
319 g_video_mode_num = 0;
320 g_video_mode_max = 1024;
321 g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max);
322 if (!g_video_mode_list)
323 {
324 return 0;
325 }
326
327 #ifdef GRUB_MACHINE_PCBIOS
328 grub_dl_load ("vbe");
329 #endif
330
331 id = grub_video_get_driver_id ();
332
333 FOR_VIDEO_ADAPTERS (adapter)
334 {
335 if (!adapter->iterate ||
336 (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE ||
337 adapter->init() != GRUB_ERR_NONE)))
338 {
339 continue;
340 }
341
342 adapter->iterate(ventoy_video_hook, NULL);
343
344 if (adapter->id != id)
345 {
346 adapter->fini();
347 }
348 }
349
350 /* sort video mode */
351 for (i = 0; i < g_video_mode_num; i++)
352 for (j = i + 1; j < g_video_mode_num; j++)
353 {
354 if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0)
355 {
356 grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode));
357 grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode));
358 grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode));
359 }
360 }
361
362 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
363 }
364
365 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
366 {
367 int len;
368 grub_file_t file;
369 static struct grub_fs vtoy_fs =
370 {
371 .name = "vtoy",
372 .fs_dir = 0,
373 .fs_open = 0,
374 .fs_read = ventoy_fs_read,
375 .fs_close = ventoy_fs_close,
376 .fs_label = 0,
377 .next = 0
378 };
379
380 if (type != 52)
381 {
382 return rawFile;
383 }
384
385 file = (grub_file_t)grub_zalloc(sizeof (*file));
386 if (!file)
387 {
388 return 0;
389 }
390
391 file->data = grub_malloc(rawFile->size + 4096);
392 if (!file->data)
393 {
394 return 0;
395 }
396
397 grub_file_read(rawFile, file->data, rawFile->size);
398 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
399
400 g_old_file = rawFile;
401
402 file->size = rawFile->size + len;
403 file->device = rawFile->device;
404 file->fs = &vtoy_fs;
405 file->not_easily_seekable = 1;
406
407 return file;
408 }
409
410 static int ventoy_check_decimal_var(const char *name, long *value)
411 {
412 const char *value_str = NULL;
413
414 value_str = grub_env_get(name);
415 if (NULL == value_str)
416 {
417 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
418 }
419
420 if (!ventoy_is_decimal(value_str))
421 {
422 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
423 }
424
425 *value = grub_strtol(value_str, NULL, 10);
426
427 return GRUB_ERR_NONE;
428 }
429
430 grub_uint64_t ventoy_get_vtoy_partsize(int part)
431 {
432 grub_uint64_t sectors;
433
434 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
435 {
436 sectors = g_ventoy_part_info->PartTbl[part].LastLBA + 1 - g_ventoy_part_info->PartTbl[part].StartLBA;
437 }
438 else
439 {
440 sectors = g_ventoy_part_info->MBR.PartTbl[part].SectorCount;
441 }
442
443 return sectors * 512;
444 }
445
446 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
447 {
448 int len;
449 grub_file_t file;
450 char exec[128];
451 char *data = NULL;
452 grub_uint32_t offset;
453
454 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
455 if (file == NULL)
456 {
457 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
458 return 1;
459 }
460
461 len = (int)file->size;
462
463 data = (char *)grub_malloc(file->size);
464 if (!data)
465 {
466 return 1;
467 }
468
469 grub_file_read(file, data, file->size);
470 grub_file_close(file);
471
472 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
473 grub_script_execute_sourcecode(exec);
474
475 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
476 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
477 grub_file_close(file);
478
479 grub_script_execute_sourcecode("loopback -d efiboot");
480
481 *buf = data;
482 *datalen = len;
483 *direntoff = offset + 2;
484
485 return 0;
486 }
487
488 static int ventoy_set_check_result(int ret, const char *msg)
489 {
490 char buf[32];
491
492 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
493 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
494 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
495
496 if (ret)
497 {
498 grub_printf(VTOY_WARNING"\n");
499 grub_printf(VTOY_WARNING"\n");
500 grub_printf(VTOY_WARNING"\n\n\n");
501
502 grub_printf("This is NOT a standard Ventoy device and is NOT supported (%d).\n", ret);
503 grub_printf("Error message: <%s>\n\n", msg);
504 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
505
506 grub_printf("\n\nWill exit after 10 seconds ...... ");
507 grub_refresh();
508 grub_sleep(10);
509 }
510
511 return ret;
512 }
513
514 static int ventoy_check_official_device(grub_device_t dev)
515 {
516 int workaround = 0;
517 grub_file_t file;
518 grub_uint64_t offset;
519 char devname[64];
520 grub_fs_t fs;
521 grub_uint8_t mbr[512];
522 grub_disk_t disk;
523 grub_device_t dev2;
524 char *label = NULL;
525 struct grub_partition *partition;
526
527 if (dev->disk == NULL || dev->disk->partition == NULL)
528 {
529 return ventoy_set_check_result(1 | 0x1000, "Internal Error");
530 }
531
532 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
533 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
534 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
535 {
536 #ifndef GRUB_MACHINE_EFI
537 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name))
538 {
539 return ventoy_set_check_result(2 | 0x1000, "File ventoy/ventoy.cpio missing in VTOYEFI partition");
540 }
541 else if (0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name))
542 {
543 return ventoy_set_check_result(2 | 0x1000, "File grub/localboot.cfg missing in VTOYEFI partition");
544 }
545 else if (0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
546 {
547 return ventoy_set_check_result(2 | 0x1000, "File tool/mount.exfat-fuse_aarch64 missing in VTOYEFI partition");
548 }
549 else
550 {
551 workaround = 1;
552 }
553 #endif
554 }
555
556 /* We must have partition 2 */
557 if (workaround)
558 {
559 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
560 }
561 else
562 {
563 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
564 }
565 if (!file)
566 {
567 return ventoy_set_check_result(3 | 0x1000, "File ventoy/ventoy.cpio open failed in VTOYEFI partition");
568 }
569
570 if (NULL == grub_strstr(file->fs->name, "fat"))
571 {
572 grub_file_close(file);
573 return ventoy_set_check_result(4 | 0x1000, "VTOYEFI partition is not FAT filesystem");
574 }
575
576 partition = dev->disk->partition;
577 if (partition->number != 0 || partition->start != 2048)
578 {
579 return ventoy_set_check_result(5, "Ventoy partition is not start at 1MB");
580 }
581
582 if (workaround)
583 {
584 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
585 {
586 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
587 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
588 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
589 {
590 grub_file_close(file);
591 return ventoy_set_check_result(6, "Disk partition layout check failed.");
592 }
593 }
594 else
595 {
596 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
597 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
598 PartTbl[1].SectorCount != 65536)
599 {
600 grub_file_close(file);
601 return ventoy_set_check_result(6, "Disk partition layout check failed.");
602 }
603 }
604 }
605 else
606 {
607 offset = partition->start + partition->len;
608 partition = file->device->disk->partition;
609 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
610 {
611 grub_file_close(file);
612 return ventoy_set_check_result(7, "Disk partition layout check failed.");
613 }
614 }
615
616 grub_file_close(file);
617
618 if (workaround == 0)
619 {
620 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
621 dev2 = grub_device_open(devname);
622 if (!dev2)
623 {
624 return ventoy_set_check_result(8, "Disk open failed");
625 }
626
627 fs = grub_fs_probe(dev2);
628 if (!fs)
629 {
630 grub_device_close(dev2);
631 return ventoy_set_check_result(9, "FS probe failed");
632 }
633
634 fs->fs_label(dev2, &label);
635 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
636 {
637 grub_device_close(dev2);
638 return ventoy_set_check_result(10, "Partition name is not VTOYEFI");
639 }
640
641 grub_device_close(dev2);
642 }
643
644 /* MBR check */
645 disk = grub_disk_open(dev->disk->name);
646 if (!disk)
647 {
648 return ventoy_set_check_result(11, "Disk open failed");
649 }
650
651 grub_memset(mbr, 0, 512);
652 grub_disk_read(disk, 0, 0, 512, mbr);
653 grub_disk_close(disk);
654
655 if (grub_memcmp(g_check_mbr_data, mbr, 0x30) || grub_memcmp(g_check_mbr_data + 0x30, mbr + 0x190, 16))
656 {
657 return ventoy_set_check_result(12, "MBR check failed");
658 }
659
660 return ventoy_set_check_result(0, NULL);
661 }
662
663 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
664 {
665 if (0 == info->dir)
666 {
667 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
668 {
669 *((int *)data) = 1;
670 return 0;
671 }
672 }
673
674 return 0;
675 }
676
677 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
678 {
679 grub_uint64_t size = 0;
680 grub_file_t file;
681 va_list ap;
682 char fullpath[256] = {0};
683
684 va_start (ap, fmt);
685 grub_vsnprintf(fullpath, 255, fmt, ap);
686 va_end (ap);
687
688 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
689 if (!file)
690 {
691 debug("grub_file_open failed <%s>\n", fullpath);
692 grub_errno = 0;
693 return 0;
694 }
695
696 size = file->size;
697 grub_file_close(file);
698 return size;
699 }
700
701 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
702 {
703 va_list ap;
704 grub_file_t file;
705 char fullpath[512] = {0};
706
707 va_start (ap, fmt);
708 grub_vsnprintf(fullpath, 511, fmt, ap);
709 va_end (ap);
710
711 file = grub_file_open(fullpath, type);
712 if (!file)
713 {
714 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
715 grub_errno = 0;
716 }
717
718 return file;
719 }
720
721 int ventoy_is_dir_exist(const char *fmt, ...)
722 {
723 va_list ap;
724 int len;
725 char *pos = NULL;
726 char buf[512] = {0};
727
728 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
729 pos = buf + 6;
730
731 va_start (ap, fmt);
732 len = grub_vsnprintf(pos, 511, fmt, ap);
733 va_end (ap);
734
735 grub_strncpy(pos + len, "\" ]", 3);
736
737 debug("script exec %s\n", buf);
738
739 if (0 == grub_script_execute_sourcecode(buf))
740 {
741 return 1;
742 }
743
744 return 0;
745 }
746
747 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
748 {
749 mz_stream s;
750 grub_uint8_t *outbuf;
751 grub_uint8_t gzHdr[10] =
752 {
753 0x1F, 0x8B, /* magic */
754 8, /* z method */
755 0, /* flags */
756 0,0,0,0, /* mtime */
757 4, /* xfl */
758 3, /* OS */
759 };
760
761 grub_memset(&s, 0, sizeof(mz_stream));
762
763 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
764
765 outbuf = (grub_uint8_t *)mem_out;
766
767 mem_out_len -= sizeof(gzHdr) + 8;
768 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
769 outbuf += sizeof(gzHdr);
770
771 s.avail_in = mem_in_len;
772 s.next_in = mem_in;
773
774 s.avail_out = mem_out_len;
775 s.next_out = outbuf;
776
777 mz_deflate(&s, MZ_FINISH);
778
779 mz_deflateEnd(&s);
780
781 outbuf += s.total_out;
782 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
783 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
784
785 return s.total_out + sizeof(gzHdr) + 8;
786 }
787
788
789 #if 0
790 ventoy grub cmds
791 #endif
792
793 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
794 {
795 if (argc != 1)
796 {
797 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
798 }
799
800 if (0 == grub_strcmp(args[0], "on"))
801 {
802 g_ventoy_debug = 1;
803 grub_env_set("vtdebug_flag", "debug");
804 }
805 else
806 {
807 g_ventoy_debug = 0;
808 grub_env_set("vtdebug_flag", "");
809 }
810
811 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
812 }
813
814 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
815 {
816 (void)ctxt;
817
818 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
819 {
820 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
821 grub_printf(" level:\r\n");
822 grub_printf(" 01/11: busybox / (+cat log)\r\n");
823 grub_printf(" 02/12: initrd / (+cat log)\r\n");
824 grub_printf(" 03/13: hook / (+cat log)\r\n");
825 grub_printf("\r\n");
826 grub_printf(" debug:\r\n");
827 grub_printf(" 0: debug is off\r\n");
828 grub_printf(" 1: debug is on\r\n");
829 grub_printf("\r\n");
830 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
831 }
832
833 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
834
835 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
836 {
837 g_ventoy_debug_level = 1;
838 }
839
840 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
841 }
842
843 static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
844 {
845 (void)ctxt;
846
847 if (argc != 2)
848 {
849 return 1;
850 }
851
852 return (grub_strstr(args[0], args[1])) ? 0 : 1;
853 }
854
855 static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
856 {
857 char *c0, *c1;
858
859 (void)ctxt;
860
861 if (argc != 2)
862 {
863 return 1;
864 }
865
866 c0 = args[0];
867 c1 = args[1];
868
869 while (*c0 && *c1)
870 {
871 if (*c0 != *c1)
872 {
873 return 1;
874 }
875 c0++;
876 c1++;
877 }
878
879 if (*c1)
880 {
881 return 1;
882 }
883
884 return 0;
885 }
886
887 static grub_err_t ventoy_cmd_strcasebegin(grub_extcmd_context_t ctxt, int argc, char **args)
888 {
889 char *c0, *c1;
890
891 (void)ctxt;
892
893 if (argc != 2)
894 {
895 return 1;
896 }
897
898 c0 = args[0];
899 c1 = args[1];
900
901 while (*c0 && *c1)
902 {
903 if ((*c0 != *c1) && (*c0 != grub_toupper(*c1)))
904 {
905 return 1;
906 }
907 c0++;
908 c1++;
909 }
910
911 if (*c1)
912 {
913 return 1;
914 }
915
916 return 0;
917 }
918
919 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
920 {
921 long value_long = 0;
922 char buf[32];
923
924 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
925 {
926 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
927 }
928
929 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
930 {
931 return grub_errno;
932 }
933
934 value_long += grub_strtol(args[1], NULL, 10);
935
936 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
937 grub_env_set(args[0], buf);
938
939 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
940 }
941
942 static grub_err_t ventoy_cmd_mod(grub_extcmd_context_t ctxt, int argc, char **args)
943 {
944 ulonglong value1 = 0;
945 ulonglong value2 = 0;
946 char buf[32];
947
948 if (argc != 3)
949 {
950 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name);
951 }
952
953 value1 = grub_strtoull(args[0], NULL, 10);
954 value2 = grub_strtoull(args[1], NULL, 10);
955
956 grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1)));
957 grub_env_set(args[2], buf);
958
959 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
960 }
961
962 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
963 {
964 int rc = 1;
965 char buf[32];
966 grub_file_t file;
967
968 (void)ctxt;
969 (void)argc;
970 (void)args;
971
972 if (argc != 2)
973 {
974 return rc;
975 }
976
977 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
978 if (file == NULL)
979 {
980 debug("failed to open file <%s> for udf check\n", args[0]);
981 return 1;
982 }
983
984 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
985
986 grub_env_set(args[1], buf);
987
988 grub_file_close(file);
989 rc = 0;
990
991 return rc;
992 }
993
994 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
995 {
996 grub_file_t file;
997
998 (void)ctxt;
999 (void)argc;
1000 (void)args;
1001
1002 g_wimboot_enable = 0;
1003 g_wimiso_size = 0;
1004 grub_check_free(g_wimiso_path);
1005 grub_check_free(g_wimiso_chunk_list.chunk);
1006
1007 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
1008 if (!file)
1009 {
1010 return 0;
1011 }
1012
1013 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
1014 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1015 if (NULL == g_wimiso_chunk_list.chunk)
1016 {
1017 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1018 }
1019
1020 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1021 g_wimiso_chunk_list.cur_chunk = 0;
1022
1023 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
1024
1025 g_wimboot_enable = 1;
1026 g_wimiso_path = grub_strdup(args[0]);
1027 g_wimiso_size = (grub_uint32_t)(file->size);
1028 grub_file_close(file);
1029
1030 return 0;
1031 }
1032
1033 static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
1034 {
1035 int len = 0;
1036 int totlen = 0;
1037 int offset = 0;
1038 grub_file_t file;
1039 char name[32];
1040 char value[32];
1041 char *buf = NULL;
1042 char *data = NULL;
1043 ventoy_iso9660_override *dirent;
1044
1045 (void)ctxt;
1046
1047 if (argc != 2)
1048 {
1049 return 1;
1050 }
1051
1052 totlen = sizeof(ventoy_chain_head);
1053
1054 if (ventoy_load_efiboot_template(&buf, &len, &offset))
1055 {
1056 debug("failed to load efiboot template %d\n", len);
1057 return 1;
1058 }
1059
1060 totlen += len;
1061
1062 debug("efiboot template len:%d offset:%d\n", len, offset);
1063
1064 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
1065 if (file == NULL)
1066 {
1067 debug("failed to open file <%s>\n", args[0]);
1068 return 1;
1069 }
1070
1071 if (grub_strncmp(args[0], g_iso_path, grub_strlen(g_iso_path)))
1072 {
1073 file->vlnk = 1;
1074 }
1075
1076 totlen += ventoy_align_2k(file->size);
1077
1078 dirent = (ventoy_iso9660_override *)(buf + offset);
1079 dirent->first_sector = len / 2048;
1080 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
1081 dirent->size = (grub_uint32_t)file->size;
1082 dirent->size_be = grub_swap_bytes32(dirent->size);
1083
1084 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
1085
1086 #ifdef GRUB_MACHINE_EFI
1087 data = (char *)grub_efi_allocate_iso_buf(totlen);
1088 #else
1089 data = (char *)grub_malloc(totlen);
1090 #endif
1091
1092 ventoy_fill_os_param(file, (ventoy_os_param *)data);
1093
1094 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
1095 grub_check_free(buf);
1096
1097 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
1098 grub_file_close(file);
1099
1100 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1101 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
1102 grub_env_set(name, value);
1103
1104 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1105 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
1106 grub_env_set(name, value);
1107
1108 return 0;
1109 }
1110
1111 grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args)
1112 {
1113 (void)ctxt;
1114 (void)argc;
1115 (void)args;
1116
1117 g_vtoy_load_prompt = 0;
1118 grub_memset(g_vtoy_prompt_msg, 0, sizeof(g_vtoy_prompt_msg));
1119
1120 if (argc == 2 && args[0][0] == '1')
1121 {
1122 g_vtoy_load_prompt = 1;
1123 grub_snprintf(g_vtoy_prompt_msg, sizeof(g_vtoy_prompt_msg), "%s", args[1]);
1124 }
1125
1126 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1127 }
1128
1129 int ventoy_need_prompt_load_file(void)
1130 {
1131 return g_vtoy_load_prompt;
1132 }
1133
1134 grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size)
1135 {
1136 grub_uint64_t ro = 0;
1137 grub_uint64_t div = 0;
1138 grub_ssize_t left = size;
1139 char *cur = (char *)buf;
1140
1141 grub_printf("\r%s 1%% ", g_vtoy_prompt_msg);
1142 grub_refresh();
1143
1144 while (left >= VTOY_SIZE_2MB)
1145 {
1146 grub_file_read(file, cur, VTOY_SIZE_2MB);
1147 cur += VTOY_SIZE_2MB;
1148 left -= VTOY_SIZE_2MB;
1149
1150 div = grub_divmod64((grub_uint64_t)((size - left) * 100), (grub_uint64_t)size, &ro);
1151 grub_printf("\r%s %d%% ", g_vtoy_prompt_msg, (int)div);
1152 grub_refresh();
1153 }
1154
1155 if (left > 0)
1156 {
1157 grub_file_read(file, cur, left);
1158 }
1159
1160 grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg);
1161 grub_refresh();
1162
1163 return size;
1164 }
1165
1166 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
1167 {
1168 int rc = 1;
1169 char name[32];
1170 char value[32];
1171 char *buf = NULL;
1172 grub_file_t file;
1173 enum grub_file_type type;
1174
1175 (void)ctxt;
1176 (void)argc;
1177 (void)args;
1178
1179 if (argc != 3)
1180 {
1181 return rc;
1182 }
1183
1184 if (grub_strcmp(args[0], "nodecompress") == 0)
1185 {
1186 type = VENTOY_FILE_TYPE;
1187 }
1188 else
1189 {
1190 type = GRUB_FILE_TYPE_LINUX_INITRD;
1191 }
1192
1193 file = ventoy_grub_file_open(type, "%s", args[1]);
1194 if (file == NULL)
1195 {
1196 debug("failed to open file <%s>\n", args[1]);
1197 return 1;
1198 }
1199
1200 #ifdef GRUB_MACHINE_EFI
1201 buf = (char *)grub_efi_allocate_chain_buf(file->size);
1202 #else
1203 buf = (char *)grub_malloc(file->size);
1204 #endif
1205
1206 if (!buf)
1207 {
1208 grub_file_close(file);
1209 return 1;
1210 }
1211
1212 if (g_vtoy_load_prompt)
1213 {
1214 ventoy_load_file_with_prompt(file, buf, file->size);
1215 }
1216 else
1217 {
1218 grub_file_read(file, buf, file->size);
1219 }
1220
1221 grub_snprintf(name, sizeof(name), "%s_addr", args[2]);
1222 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1223 grub_env_set(name, value);
1224
1225 grub_snprintf(name, sizeof(name), "%s_size", args[2]);
1226 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1227 grub_env_set(name, value);
1228
1229 grub_file_close(file);
1230 rc = 0;
1231
1232 return rc;
1233 }
1234
1235 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
1236 {
1237 int rc = 1;
1238 int headlen;
1239 char name[32];
1240 char value[32];
1241 char *buf = NULL;
1242 grub_file_t file;
1243
1244 (void)ctxt;
1245 (void)argc;
1246 (void)args;
1247
1248 if (argc != 2)
1249 {
1250 return rc;
1251 }
1252
1253 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1254 if (file == NULL)
1255 {
1256 debug("failed to open file <%s> for udf check\n", args[0]);
1257 return 1;
1258 }
1259
1260 headlen = sizeof(ventoy_chain_head);
1261
1262 #ifdef GRUB_MACHINE_EFI
1263 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
1264 #else
1265 buf = (char *)grub_malloc(headlen + file->size);
1266 #endif
1267
1268 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
1269
1270 grub_file_read(file, buf + headlen, file->size);
1271
1272 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1273 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1274 grub_env_set(name, value);
1275
1276 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1277 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1278 grub_env_set(name, value);
1279
1280 grub_file_close(file);
1281 rc = 0;
1282
1283 return rc;
1284 }
1285
1286 static grub_err_t ventoy_cmd_iso9660_is_joliet(grub_extcmd_context_t ctxt, int argc, char **args)
1287 {
1288 (void)ctxt;
1289 (void)argc;
1290 (void)args;
1291
1292 if (grub_iso9660_is_joliet())
1293 {
1294 debug("This time has joliet process\n");
1295 return 0;
1296 }
1297 else
1298 {
1299 return 1;
1300 }
1301 }
1302
1303 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
1304 {
1305 (void)ctxt;
1306
1307 if (argc != 1)
1308 {
1309 return 1;
1310 }
1311
1312 if (args[0][0] == '1')
1313 {
1314 grub_iso9660_set_nojoliet(1);
1315 }
1316 else
1317 {
1318 grub_iso9660_set_nojoliet(0);
1319 }
1320
1321 return 0;
1322 }
1323
1324 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
1325 {
1326 int i;
1327 int rc = 1;
1328 grub_file_t file;
1329 grub_uint8_t buf[32];
1330
1331 (void)ctxt;
1332 (void)argc;
1333 (void)args;
1334
1335 if (argc != 1)
1336 {
1337 return rc;
1338 }
1339
1340 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1341 if (file == NULL)
1342 {
1343 debug("failed to open file <%s> for udf check\n", args[0]);
1344 return 1;
1345 }
1346
1347 for (i = 16; i < 32; i++)
1348 {
1349 grub_file_seek(file, i * 2048);
1350 grub_file_read(file, buf, sizeof(buf));
1351 if (buf[0] == 255)
1352 {
1353 break;
1354 }
1355 }
1356
1357 i++;
1358 grub_file_seek(file, i * 2048);
1359 grub_file_read(file, buf, sizeof(buf));
1360
1361 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
1362 {
1363 i++;
1364 grub_file_seek(file, i * 2048);
1365 grub_file_read(file, buf, sizeof(buf));
1366
1367 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
1368 grub_memcmp(buf + 1, "NSR03", 5) == 0)
1369 {
1370 rc = 0;
1371 }
1372 }
1373
1374 grub_file_close(file);
1375
1376 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
1377
1378 return rc;
1379 }
1380
1381 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
1382 {
1383 long value_long1 = 0;
1384 long value_long2 = 0;
1385
1386 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
1387 {
1388 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
1389 }
1390
1391 value_long1 = grub_strtol(args[0], NULL, 10);
1392 value_long2 = grub_strtol(args[2], NULL, 10);
1393
1394 if (0 == grub_strcmp(args[1], "eq"))
1395 {
1396 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1397 }
1398 else if (0 == grub_strcmp(args[1], "ne"))
1399 {
1400 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1401 }
1402 else if (0 == grub_strcmp(args[1], "gt"))
1403 {
1404 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1405 }
1406 else if (0 == grub_strcmp(args[1], "lt"))
1407 {
1408 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1409 }
1410 else if (0 == grub_strcmp(args[1], "ge"))
1411 {
1412 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1413 }
1414 else if (0 == grub_strcmp(args[1], "le"))
1415 {
1416 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1417 }
1418 else
1419 {
1420 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
1421 }
1422
1423 return grub_errno;
1424 }
1425
1426 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
1427 {
1428 char *pos = NULL;
1429 char buf[128] = {0};
1430
1431 if (argc != 2)
1432 {
1433 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
1434 }
1435
1436 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
1437 pos = grub_strstr(buf, ",");
1438 if (pos)
1439 {
1440 *pos = 0;
1441 }
1442
1443 grub_env_set(args[1], buf);
1444
1445 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1446 }
1447
1448 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
1449 {
1450 int i;
1451 char buf[256];
1452 grub_disk_t disk;
1453 char *pos = NULL;
1454 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
1455
1456 (void)ctxt;
1457
1458 if (argc != 1)
1459 {
1460 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
1461 }
1462
1463 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
1464 {
1465 grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]);
1466 if (0 == grub_script_execute_sourcecode(buf))
1467 {
1468 debug("file %s exist, ventoy_compatible YES\n", buf);
1469 grub_env_set("ventoy_compatible", "YES");
1470 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1471 }
1472 else
1473 {
1474 debug("file %s NOT exist\n", buf);
1475 }
1476 }
1477
1478 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
1479 pos = grub_strstr(buf, ")");
1480 if (pos)
1481 {
1482 *pos = 0;
1483 }
1484
1485 disk = grub_disk_open(buf);
1486 if (disk)
1487 {
1488 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
1489 grub_disk_close(disk);
1490
1491 g_img_swap_tmp_buf[703] = 0;
1492 for (i = 318; i < 703; i++)
1493 {
1494 if (g_img_swap_tmp_buf[i] == 'V' &&
1495 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
1496 {
1497 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
1498 grub_env_set("ventoy_compatible", "YES");
1499 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1500 }
1501 }
1502 }
1503 else
1504 {
1505 debug("failed to open disk <%s>\n", buf);
1506 }
1507
1508 grub_env_set("ventoy_compatible", "NO");
1509 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1510 }
1511
1512 int ventoy_cmp_img(img_info *img1, img_info *img2)
1513 {
1514 char *s1, *s2;
1515 int c1 = 0;
1516 int c2 = 0;
1517
1518 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1519 {
1520 return (img1->plugin_list_index - img2->plugin_list_index);
1521 }
1522
1523 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1524 {
1525 c1 = *s1;
1526 c2 = *s2;
1527
1528 if (0 == g_sort_case_sensitive)
1529 {
1530 if (grub_islower(c1))
1531 {
1532 c1 = c1 - 'a' + 'A';
1533 }
1534
1535 if (grub_islower(c2))
1536 {
1537 c2 = c2 - 'a' + 'A';
1538 }
1539 }
1540
1541 if (c1 != c2)
1542 {
1543 break;
1544 }
1545 }
1546
1547 return (c1 - c2);
1548 }
1549
1550 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1551 {
1552 char *s1, *s2;
1553 int c1 = 0;
1554 int c2 = 0;
1555
1556 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1557 {
1558 return (node1->plugin_list_index - node2->plugin_list_index);
1559 }
1560
1561 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1562 {
1563 c1 = *s1;
1564 c2 = *s2;
1565
1566 if (0 == g_sort_case_sensitive)
1567 {
1568 if (grub_islower(c1))
1569 {
1570 c1 = c1 - 'a' + 'A';
1571 }
1572
1573 if (grub_islower(c2))
1574 {
1575 c2 = c2 - 'a' + 'A';
1576 }
1577 }
1578
1579 if (c1 != c2)
1580 {
1581 break;
1582 }
1583 }
1584
1585 return (c1 - c2);
1586 }
1587
1588 void ventoy_swap_img(img_info *img1, img_info *img2)
1589 {
1590 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1591
1592 grub_memcpy(img1, img2, sizeof(img_info));
1593 img1->next = g_img_swap_tmp.next;
1594 img1->prev = g_img_swap_tmp.prev;
1595
1596 g_img_swap_tmp.next = img2->next;
1597 g_img_swap_tmp.prev = img2->prev;
1598 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1599 }
1600
1601 int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1602 {
1603 (void)namelen;
1604
1605 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1606 {
1607 return 0;
1608 }
1609
1610 return 1;
1611 }
1612
1613 static int ventoy_vlnk_iterate_partition(struct grub_disk *disk, const grub_partition_t partition, void *data)
1614 {
1615 ventoy_vlnk_part *node = NULL;
1616 grub_uint32_t SelfSig;
1617 grub_uint32_t *pSig = (grub_uint32_t *)data;
1618
1619 /* skip Ventoy partition 1/2 */
1620 grub_memcpy(&SelfSig, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
1621 if (partition->number < 2 && SelfSig == *pSig)
1622 {
1623 return 0;
1624 }
1625
1626 node = grub_zalloc(sizeof(ventoy_vlnk_part));
1627 if (node)
1628 {
1629 node->disksig = *pSig;
1630 node->partoffset = (partition->start << GRUB_DISK_SECTOR_BITS);
1631 grub_snprintf(node->disk, sizeof(node->disk) - 1, "%s", disk->name);
1632 grub_snprintf(node->device, sizeof(node->device) - 1, "%s,%d", disk->name, partition->number + 1);
1633
1634 node->next = g_vlnk_part_list;
1635 g_vlnk_part_list = node;
1636 }
1637
1638 return 0;
1639 }
1640
1641 static int ventoy_vlnk_iterate_disk(const char *name, void *data)
1642 {
1643 grub_disk_t disk;
1644 grub_uint32_t sig;
1645
1646 (void)data;
1647
1648 disk = grub_disk_open(name);
1649 if (disk)
1650 {
1651 grub_disk_read(disk, 0, 0x1b8, 4, &sig);
1652 grub_partition_iterate(disk, ventoy_vlnk_iterate_partition, &sig);
1653 grub_disk_close(disk);
1654 }
1655
1656 return 0;
1657 }
1658
1659 static int ventoy_vlnk_probe_fs(ventoy_vlnk_part *cur)
1660 {
1661 const char *fs[ventoy_fs_max + 1] =
1662 {
1663 "exfat", "ntfs", "ext2", "xfs", "udf", "fat", NULL
1664 };
1665
1666 if (!cur->dev)
1667 {
1668 cur->dev = grub_device_open(cur->device);
1669 }
1670
1671 if (cur->dev)
1672 {
1673 cur->fs = grub_fs_list_probe(cur->dev, fs);
1674 }
1675
1676 return 0;
1677 }
1678
1679 static int ventoy_check_vlnk_data(ventoy_vlnk *vlnk, int print, char *dst, int size)
1680 {
1681 int diskfind = 0;
1682 int partfind = 0;
1683 int filefind = 0;
1684 char *disk, *device;
1685 grub_uint32_t readcrc, calccrc;
1686 ventoy_vlnk_part *cur;
1687 grub_fs_t fs = NULL;
1688
1689 if (grub_memcmp(&(vlnk->guid), &g_ventoy_guid, sizeof(ventoy_guid)))
1690 {
1691 if (print)
1692 {
1693 grub_printf("VLNK invalid guid\n");
1694 grub_refresh();
1695 }
1696 return 1;
1697 }
1698
1699 readcrc = vlnk->crc32;
1700 vlnk->crc32 = 0;
1701 calccrc = grub_getcrc32c(0, vlnk, sizeof(ventoy_vlnk));
1702 if (readcrc != calccrc)
1703 {
1704 if (print)
1705 {
1706 grub_printf("VLNK invalid crc 0x%08x 0x%08x\n", calccrc, readcrc);
1707 grub_refresh();
1708 }
1709 return 1;
1710 }
1711
1712 if (!g_vlnk_part_list)
1713 {
1714 grub_disk_dev_iterate(ventoy_vlnk_iterate_disk, NULL);
1715 }
1716
1717 for (cur = g_vlnk_part_list; cur && filefind == 0; cur = cur->next)
1718 {
1719 if (cur->disksig == vlnk->disk_signature)
1720 {
1721 diskfind = 1;
1722 disk = cur->disk;
1723 if (cur->partoffset == vlnk->part_offset)
1724 {
1725 partfind = 1;
1726 device = cur->device;
1727
1728 if (cur->probe == 0)
1729 {
1730 cur->probe = 1;
1731 ventoy_vlnk_probe_fs(cur);
1732 }
1733
1734 if (!fs)
1735 {
1736 fs = cur->fs;
1737 }
1738
1739 if (cur->fs)
1740 {
1741 struct grub_file file;
1742
1743 grub_memset(&file, 0, sizeof(file));
1744 file.device = cur->dev;
1745 if (cur->fs->fs_open(&file, vlnk->filepath) == GRUB_ERR_NONE)
1746 {
1747 filefind = 1;
1748 cur->fs->fs_close(&file);
1749 grub_snprintf(dst, size - 1, "(%s)%s", cur->device, vlnk->filepath);
1750 }
1751 }
1752 }
1753 }
1754 }
1755
1756 if (print)
1757 {
1758 grub_printf("\n==== VLNK Information ====\n"
1759 "Disk Signature: %08x\n"
1760 "Partition Offset: %llu\n"
1761 "File Path: <%s>\n\n",
1762 vlnk->disk_signature, (ulonglong)vlnk->part_offset, vlnk->filepath);
1763
1764 if (diskfind)
1765 {
1766 grub_printf("Disk Find: [ YES ] [ %s ]\n", disk);
1767 }
1768 else
1769 {
1770 grub_printf("Disk Find: [ NO ]\n");
1771 }
1772
1773 if (partfind)
1774 {
1775 grub_printf("Part Find: [ YES ] [ %s ] [ %s ]\n", device, fs ? fs->name : "N/A");
1776 }
1777 else
1778 {
1779 grub_printf("Part Find: [ NO ]\n");
1780 }
1781 grub_printf("File Find: [ %s ]\n", filefind ? "YES" : "NO");
1782 if (filefind)
1783 {
1784 grub_printf("VLNK File: <%s>\n", dst);
1785 }
1786
1787 grub_printf("\n");
1788 grub_refresh();
1789 }
1790
1791 return (1 - filefind);
1792 }
1793
1794 int ventoy_add_vlnk_file(char *dir, const char *name)
1795 {
1796 int rc = 1;
1797 char src[512];
1798 char dst[512];
1799 grub_file_t file = NULL;
1800 ventoy_vlnk vlnk;
1801
1802 if (!dir)
1803 {
1804 grub_snprintf(src, sizeof(src), "%s%s", g_iso_path, name);
1805 }
1806 else if (dir[0] == '/')
1807 {
1808 grub_snprintf(src, sizeof(src), "%s%s%s", g_iso_path, dir, name);
1809 }
1810 else
1811 {
1812 grub_snprintf(src, sizeof(src), "%s/%s%s", g_iso_path, dir, name);
1813 }
1814
1815 file = grub_file_open(src, VENTOY_FILE_TYPE);
1816 if (!file)
1817 {
1818 return 1;
1819 }
1820
1821 grub_memset(&vlnk, 0, sizeof(vlnk));
1822 grub_file_read(file, &vlnk, sizeof(vlnk));
1823 grub_file_close(file);
1824
1825 if (ventoy_check_vlnk_data(&vlnk, 0, dst, sizeof(dst)) == 0)
1826 {
1827 rc = grub_file_add_vlnk(src, dst);
1828 }
1829
1830 return rc;
1831 }
1832
1833 static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1834 {
1835 //int i = 0;
1836 int type = 0;
1837 int ignore = 0;
1838 int index = 0;
1839 int vlnk = 0;
1840 grub_size_t len;
1841 img_info *img;
1842 img_info *tail;
1843 const menu_tip *tip;
1844 img_iterator_node *tmp;
1845 img_iterator_node *new_node;
1846 img_iterator_node *node = (img_iterator_node *)data;
1847
1848 if (g_enumerate_time_checked == 0)
1849 {
1850 g_enumerate_finish_time_ms = grub_get_time_ms();
1851 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1852 {
1853 grub_cls();
1854 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1855 grub_refresh();
1856 g_enumerate_time_checked = 1;
1857 }
1858 }
1859
1860 len = grub_strlen(filename);
1861
1862 if (info->dir)
1863 {
1864 if (node->level + 1 > g_img_max_search_level)
1865 {
1866 return 0;
1867 }
1868
1869 if ((len == 1 && filename[0] == '.') ||
1870 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1871 {
1872 return 0;
1873 }
1874
1875 if (!ventoy_img_name_valid(filename, len))
1876 {
1877 return 0;
1878 }
1879
1880 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1881 {
1882 return 0;
1883 }
1884
1885 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1886 {
1887 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1888 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1889 if (index == 0)
1890 {
1891 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1892 return 0;
1893 }
1894 }
1895
1896 new_node = grub_zalloc(sizeof(img_iterator_node));
1897 if (new_node)
1898 {
1899 new_node->level = node->level + 1;
1900 new_node->plugin_list_index = index;
1901 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1902
1903 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1904 if (ignore)
1905 {
1906 debug("Directory %s ignored...\n", new_node->dir);
1907 grub_free(new_node);
1908 return 0;
1909 }
1910
1911 new_node->tail = node->tail;
1912
1913 new_node->parent = node;
1914 if (!node->firstchild)
1915 {
1916 node->firstchild = new_node;
1917 }
1918
1919 if (g_img_iterator_tail)
1920 {
1921 g_img_iterator_tail->next = new_node;
1922 g_img_iterator_tail = new_node;
1923 }
1924 else
1925 {
1926 g_img_iterator_head.next = new_node;
1927 g_img_iterator_tail = new_node;
1928 }
1929 }
1930 }
1931 else
1932 {
1933 debug("Find a file %s\n", filename);
1934 if (len < 4)
1935 {
1936 return 0;
1937 }
1938
1939 if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso"))
1940 {
1941 type = img_type_iso;
1942 }
1943 else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1944 {
1945 type = img_type_wim;
1946 }
1947 else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1948 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1949 {
1950 type = img_type_vhd;
1951 }
1952 #ifdef GRUB_MACHINE_EFI
1953 else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi"))
1954 {
1955 type = img_type_efi;
1956 }
1957 #endif
1958 else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img"))
1959 {
1960 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1961 {
1962 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1963 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1964 {
1965 return 0;
1966 }
1967 }
1968 type = img_type_img;
1969 }
1970 else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1971 {
1972 type = img_type_vtoy;
1973 }
1974 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1975 {
1976 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1977 {
1978 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1979 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1980 }
1981 return 0;
1982 }
1983 else
1984 {
1985 return 0;
1986 }
1987
1988 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1989 {
1990 return 0;
1991 }
1992
1993 if (g_plugin_image_list)
1994 {
1995 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1996 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1997 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1998 {
1999 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
2000 return 0;
2001 }
2002 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
2003 {
2004 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index);
2005 return 0;
2006 }
2007 }
2008
2009 if (info->size == VTOY_FILT_MIN_FILE_SIZE || info->size == 0)
2010 {
2011 if (grub_file_is_vlnk_suffix(filename, len))
2012 {
2013 vlnk = 1;
2014 if (ventoy_add_vlnk_file(node->dir, filename) != 0)
2015 {
2016 return 0;
2017 }
2018 }
2019 }
2020
2021 img = grub_zalloc(sizeof(img_info));
2022 if (img)
2023 {
2024 img->type = type;
2025 img->plugin_list_index = index;
2026 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
2027
2028 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
2029
2030 img->size = info->size;
2031 if (vlnk || 0 == img->size)
2032 {
2033 if (node->dir[0] == '/')
2034 {
2035 img->size = ventoy_grub_get_file_size("%s%s%s", g_iso_path, node->dir, filename);
2036 }
2037 else
2038 {
2039 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
2040 }
2041 }
2042
2043 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
2044 {
2045 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
2046 grub_free(img);
2047 return 0;
2048 }
2049
2050 if (g_ventoy_img_list)
2051 {
2052 tail = *(node->tail);
2053 img->prev = tail;
2054 tail->next = img;
2055 }
2056 else
2057 {
2058 g_ventoy_img_list = img;
2059 }
2060
2061 img->id = g_ventoy_img_count;
2062 img->parent = node;
2063 if (node && NULL == node->firstiso)
2064 {
2065 node->firstiso = img;
2066 }
2067
2068 node->isocnt++;
2069 tmp = node->parent;
2070 while (tmp)
2071 {
2072 tmp->isocnt++;
2073 tmp = tmp->parent;
2074 }
2075
2076 *((img_info **)(node->tail)) = img;
2077 g_ventoy_img_count++;
2078
2079 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
2080
2081 tip = ventoy_plugin_get_menu_tip(vtoy_tip_image_file, img->path);
2082 if (tip)
2083 {
2084 img->tip1 = tip->tip1;
2085 img->tip2 = tip->tip2;
2086 }
2087
2088 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path);
2089 if (!img->class)
2090 {
2091 img->class = g_menu_class[type];
2092 }
2093 img->menu_prefix = g_menu_prefix[type];
2094
2095 if (img_type_iso == type)
2096 {
2097 if (ventoy_plugin_check_memdisk(img->path))
2098 {
2099 img->menu_prefix = "miso";
2100 }
2101 }
2102
2103 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
2104 }
2105 }
2106
2107 return 0;
2108 }
2109
2110 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
2111 {
2112 int len = GRUB_UINT_MAX;
2113 const char *value = NULL;
2114 char name[32] = {0};
2115 char plat[32] = {0};
2116 char guidstr[32] = {0};
2117 ventoy_guid guid = VENTOY_GUID;
2118 const char *fmt1 = NULL;
2119 const char *fmt2 = NULL;
2120 const char *fmt3 = NULL;
2121 grub_uint32_t *puint = (grub_uint32_t *)name;
2122 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
2123 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
2124 const char fmtcode[]={
2125 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
2126 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
2127 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
2128 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
2129 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
2130 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
2131 };
2132
2133 grub_memset(name, 0, sizeof(name));
2134 puint[0] = grub_swap_bytes32(0x56454e54);
2135 puint[3] = grub_swap_bytes32(0x4f4e0000);
2136 puint[2] = grub_swap_bytes32(0x45525349);
2137 puint[1] = grub_swap_bytes32(0x4f595f56);
2138 value = ventoy_get_env(name);
2139
2140 grub_memset(name, 0, sizeof(name));
2141 puint[1] = grub_swap_bytes32(0x5f544f50);
2142 puint[0] = grub_swap_bytes32(0x56544c45);
2143 fmt1 = ventoy_get_env(name);
2144 if (!fmt1)
2145 {
2146 fmt1 = fmtdata;
2147 }
2148
2149 grub_memset(name, 0, sizeof(name));
2150 puint[1] = grub_swap_bytes32(0x5f4c4654);
2151 puint[0] = grub_swap_bytes32(0x56544c45);
2152 fmt2 = ventoy_get_env(name);
2153
2154 grub_memset(name, 0, sizeof(name));
2155 puint[1] = grub_swap_bytes32(0x5f434c52);
2156 puint[0] = grub_swap_bytes32(0x56544c45);
2157 fmt3 = ventoy_get_env(name);
2158
2159 grub_memcpy(guidstr, &guid, sizeof(guid));
2160
2161 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
2162
2163 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
2164 #pragma GCC diagnostic push
2165 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
2166 len = grub_snprintf(buffer, buflen, fmtcode,
2167 fmt1 ? fmt1 : fmtdata,
2168 fmt2 ? fmt2 : fmtdata + 4,
2169 value ? value : "", plat, guidstr,
2170 fmt3 ? fmt3 : fmtdata + 6);
2171 #pragma GCC diagnostic pop
2172
2173 grub_memset(name, 0, sizeof(name));
2174 puint[0] = grub_swap_bytes32(0x76746f79);
2175 puint[2] = grub_swap_bytes32(0x656e7365);
2176 puint[1] = grub_swap_bytes32(0x5f6c6963);
2177 ventoy_set_env(name, guidstr);
2178
2179 return len;
2180 }
2181
2182 int ventoy_check_password(const vtoy_password *pwd, int retry)
2183 {
2184 int offset;
2185 char input[256];
2186 grub_uint8_t md5[16];
2187
2188 while (retry--)
2189 {
2190 grub_memset(input, 0, sizeof(input));
2191
2192 grub_printf("Enter password: ");
2193 grub_refresh();
2194
2195 if (pwd->type == VTOY_PASSWORD_TXT)
2196 {
2197 grub_password_get(input, 128);
2198 if (grub_strcmp(pwd->text, input) == 0)
2199 {
2200 return 0;
2201 }
2202 }
2203 else if (pwd->type == VTOY_PASSWORD_MD5)
2204 {
2205 grub_password_get(input, 128);
2206 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2207 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2208 {
2209 return 0;
2210 }
2211 }
2212 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
2213 {
2214 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
2215 grub_password_get(input + offset, 128);
2216
2217 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
2218 if (grub_memcmp(pwd->md5, md5, 16) == 0)
2219 {
2220 return 0;
2221 }
2222 }
2223
2224 grub_printf("Invalid password!\n\n");
2225 grub_refresh();
2226 }
2227
2228 return 1;
2229 }
2230
2231 static img_info * ventoy_get_min_iso(img_iterator_node *node)
2232 {
2233 img_info *minimg = NULL;
2234 img_info *img = (img_info *)(node->firstiso);
2235
2236 while (img && (img_iterator_node *)(img->parent) == node)
2237 {
2238 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
2239 {
2240 minimg = img;
2241 }
2242 img = img->next;
2243 }
2244
2245 if (minimg)
2246 {
2247 minimg->select = 1;
2248 }
2249
2250 return minimg;
2251 }
2252
2253 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
2254 {
2255 img_iterator_node *Minchild = NULL;
2256 img_iterator_node *child = node->firstchild;
2257
2258 while (child && child->parent == node)
2259 {
2260 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
2261 {
2262 Minchild = child;
2263 }
2264 child = child->next;
2265 }
2266
2267 if (Minchild)
2268 {
2269 Minchild->select = 1;
2270 }
2271
2272 return Minchild;
2273 }
2274
2275 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
2276 {
2277 int offset = 1;
2278 img_info *img = NULL;
2279 const char *dir_class = NULL;
2280 const char *dir_alias = NULL;
2281 img_iterator_node *child = NULL;
2282 const menu_tip *tip = NULL;
2283
2284 if (node->isocnt == 0 || node->done == 1)
2285 {
2286 return 0;
2287 }
2288
2289 if (node->parent && node->parent->dirlen < node->dirlen)
2290 {
2291 offset = node->parent->dirlen;
2292 }
2293
2294 if (node == &g_img_iterator_head)
2295 {
2296 if (g_default_menu_mode == 0)
2297 {
2298 if (g_tree_view_menu_style == 0)
2299 {
2300 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2301 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2302 " echo 'return ...' \n"
2303 "}\n", "<--");
2304 }
2305 else
2306 {
2307 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2308 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2309 " echo 'return ...' \n"
2310 "}\n");
2311 }
2312 }
2313
2314 g_tree_script_pre = g_tree_script_pos;
2315 }
2316 else
2317 {
2318 node->dir[node->dirlen - 1] = 0;
2319 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2320 if (!dir_class)
2321 {
2322 dir_class = "vtoydir";
2323 }
2324
2325 tip = ventoy_plugin_get_menu_tip(vtoy_tip_directory, node->dir);
2326
2327 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2328 if (dir_alias)
2329 {
2330 if (g_tree_view_menu_style == 0)
2331 {
2332 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2333 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2334 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2335 }
2336 else
2337 {
2338 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2339 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2340 dir_alias, dir_class, node->dir + offset, tip);
2341 }
2342 }
2343 else
2344 {
2345 dir_alias = node->dir + offset;
2346
2347 if (g_tree_view_menu_style == 0)
2348 {
2349 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2350 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2351 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2352 }
2353 else
2354 {
2355 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2356 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2357 dir_alias, dir_class, node->dir + offset, tip);
2358 }
2359 }
2360
2361 if (g_tree_view_menu_style == 0)
2362 {
2363 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2364 "menuentry \"%-10s [%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2365 " echo 'return ...' \n"
2366 "}\n", "<--", node->dir);
2367 }
2368 else
2369 {
2370 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2371 "menuentry \"[%s/..]\" --class=\"vtoyret\" VTOY_RET {\n "
2372 " echo 'return ...' \n"
2373 "}\n", node->dir);
2374 }
2375 }
2376
2377 while ((child = ventoy_get_min_child(node)) != NULL)
2378 {
2379 ventoy_dynamic_tree_menu(child);
2380 }
2381
2382 while ((img = ventoy_get_min_iso(node)) != NULL)
2383 {
2384 if (g_tree_view_menu_style == 0)
2385 {
2386 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2387 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2388 " %s_%s \n"
2389 "}\n",
2390 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2391 img->unsupport ? "[***********] " : "",
2392 img->alias ? img->alias : img->name, img->class, img,
2393 img->menu_prefix,
2394 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2395 }
2396 else
2397 {
2398 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2399 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2400 " %s_%s \n"
2401 "}\n",
2402 img->unsupport ? "[***********] " : "",
2403 img->alias ? img->alias : img->name, img->class, img,
2404 img->menu_prefix,
2405 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2406 }
2407 }
2408
2409 if (node != &g_img_iterator_head)
2410 {
2411 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "}\n");
2412 }
2413
2414 node->done = 1;
2415 return 0;
2416 }
2417
2418 static int ventoy_set_default_menu(void)
2419 {
2420 int img_len = 0;
2421 char *pos = NULL;
2422 char *end = NULL;
2423 char *def = NULL;
2424 const char *strdata = NULL;
2425 img_info *cur = NULL;
2426 img_info *default_node = NULL;
2427 const char *default_image = NULL;
2428
2429 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2430 if (default_image && default_image[0] == '/')
2431 {
2432 img_len = grub_strlen(default_image);
2433
2434 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2435 {
2436 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2437 {
2438 default_node = cur;
2439 break;
2440 }
2441 }
2442
2443 if (!default_node)
2444 {
2445 return 1;
2446 }
2447
2448 if (0 == g_default_menu_mode)
2449 {
2450 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2451 }
2452 else
2453 {
2454 def = grub_strdup(default_image);
2455 if (!def)
2456 {
2457 return 1;
2458 }
2459
2460 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2461
2462 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2463 if (strdata && strdata[0] == '/')
2464 {
2465 pos = def + grub_strlen(strdata);
2466 if (*pos == '/')
2467 {
2468 pos++;
2469 }
2470 }
2471 else
2472 {
2473 pos = def + 1;
2474 }
2475
2476 while ((end = grub_strchr(pos, '/')) != NULL)
2477 {
2478 *end = 0;
2479 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2480 pos = end + 1;
2481 }
2482
2483 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2484 grub_free(def);
2485 }
2486 }
2487
2488 return 0;
2489 }
2490
2491 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2492 {
2493 img_info *next = NULL;
2494 img_info *cur = g_ventoy_img_list;
2495
2496 (void)ctxt;
2497 (void)argc;
2498 (void)args;
2499
2500 while (cur)
2501 {
2502 next = cur->next;
2503 grub_free(cur);
2504 cur = next;
2505 }
2506
2507 g_ventoy_img_list = NULL;
2508 g_ventoy_img_count = 0;
2509
2510 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2511 }
2512
2513 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2514 {
2515 long img_id = 0;
2516 img_info *cur = g_ventoy_img_list;
2517
2518 (void)ctxt;
2519
2520 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2521 {
2522 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2523 }
2524
2525 img_id = grub_strtol(args[0], NULL, 10);
2526 if (img_id >= g_ventoy_img_count)
2527 {
2528 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2529 }
2530
2531 debug("Find image %ld name \n", img_id);
2532
2533 while (cur && img_id > 0)
2534 {
2535 img_id--;
2536 cur = cur->next;
2537 }
2538
2539 if (!cur)
2540 {
2541 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2542 }
2543
2544 debug("image name is %s\n", cur->name);
2545
2546 grub_env_set(args[1], cur->name);
2547
2548 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2549 }
2550
2551 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2552 {
2553 int len = 0;
2554 char id[32] = {0};
2555 img_info *cur = g_ventoy_img_list;
2556
2557 (void)ctxt;
2558
2559 if (argc != 1)
2560 {
2561 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2562 }
2563
2564 len = (int)grub_strlen(args[0]);
2565
2566 while (cur)
2567 {
2568 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2569 {
2570 break;
2571 }
2572 cur = cur->next;
2573 }
2574
2575 if (!cur)
2576 {
2577 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2578 }
2579
2580 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2581 grub_env_set("chosen", id);
2582 grub_env_export("chosen");
2583
2584 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2585 }
2586
2587 static char g_fake_vlnk_src[512];
2588 static char g_fake_vlnk_dst[512];
2589 static grub_uint64_t g_fake_vlnk_size;
2590 static grub_err_t ventoy_cmd_set_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2591 {
2592 (void)ctxt;
2593 (void)argc;
2594 (void)args;
2595
2596 g_fake_vlnk_size = (grub_uint64_t)grub_strtoull(args[2], NULL, 10);
2597
2598 grub_strncpy(g_fake_vlnk_dst, args[0], sizeof(g_fake_vlnk_dst));
2599 grub_snprintf(g_fake_vlnk_src, sizeof(g_fake_vlnk_src), "%s/________VENTOYVLNK.vlnk.%s", g_iso_path, args[1]);
2600
2601 grub_file_vtoy_vlnk(g_fake_vlnk_src, g_fake_vlnk_dst);
2602
2603 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2604 }
2605
2606 static grub_err_t ventoy_cmd_reset_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
2607 {
2608 (void)ctxt;
2609 (void)argc;
2610 (void)args;
2611
2612 g_fake_vlnk_src[0] = 0;
2613 g_fake_vlnk_dst[0] = 0;
2614 g_fake_vlnk_size = 0;
2615 grub_file_vtoy_vlnk(NULL, NULL);
2616
2617 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2618 }
2619
2620
2621 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2622 {
2623 char value[32];
2624 char *pos = NULL;
2625 char *last = NULL;
2626 const char *id = NULL;
2627 img_info *cur = NULL;
2628
2629 (void)ctxt;
2630
2631 if (argc < 1 || argc > 3)
2632 {
2633 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2634 }
2635
2636 if (g_fake_vlnk_src[0] && g_fake_vlnk_dst[0])
2637 {
2638 pos = grub_strchr(g_fake_vlnk_src, '/');
2639 grub_env_set(args[0], pos);
2640 if (argc > 1)
2641 {
2642 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(g_fake_vlnk_size));
2643 grub_env_set(args[1], value);
2644 }
2645
2646 if (argc > 2)
2647 {
2648 for (last = pos; *pos; pos++)
2649 {
2650 if (*pos == '/')
2651 {
2652 last = pos;
2653 }
2654 }
2655 grub_env_set(args[2], last + 1);
2656 }
2657
2658 goto end;
2659 }
2660
2661 id = grub_env_get("chosen");
2662
2663 pos = grub_strstr(id, "VID_");
2664 if (pos)
2665 {
2666 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2667 }
2668 else
2669 {
2670 cur = g_ventoy_img_list;
2671 }
2672
2673 if (!cur)
2674 {
2675 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2676 }
2677
2678 grub_env_set(args[0], cur->path);
2679
2680 if (argc > 1)
2681 {
2682 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2683 grub_env_set(args[1], value);
2684 }
2685
2686 if (argc > 2)
2687 {
2688 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2689 grub_env_set(args[2], cur->name);
2690 }
2691
2692 end:
2693 g_svd_replace_offset = 0;
2694
2695 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2696 }
2697
2698
2699 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2700 {
2701 int len;
2702 grub_fs_t fs;
2703 grub_device_t dev = NULL;
2704 img_info *cur = NULL;
2705 img_info *tail = NULL;
2706 img_info *min = NULL;
2707 img_info *head = NULL;
2708 const char *strdata = NULL;
2709 char *device_name = NULL;
2710 char buf[32];
2711 img_iterator_node *node = NULL;
2712 img_iterator_node *tmp = NULL;
2713
2714 (void)ctxt;
2715
2716 if (argc != 2)
2717 {
2718 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2719 }
2720
2721 if (g_ventoy_img_list || g_ventoy_img_count)
2722 {
2723 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2724 }
2725
2726 VTOY_CMD_CHECK(1);
2727
2728 g_enumerate_time_checked = 0;
2729 g_enumerate_start_time_ms = grub_get_time_ms();
2730
2731 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2732 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2733 {
2734 g_filt_dot_underscore_file = 1;
2735 }
2736
2737 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2738 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2739 {
2740 g_sort_case_sensitive = 1;
2741 }
2742
2743 device_name = grub_file_get_device_name(args[0]);
2744 if (!device_name)
2745 {
2746 goto fail;
2747 }
2748
2749 g_enum_dev = dev = grub_device_open(device_name);
2750 if (!dev)
2751 {
2752 goto fail;
2753 }
2754
2755 g_enum_fs = fs = grub_fs_probe(dev);
2756 if (!fs)
2757 {
2758 goto fail;
2759 }
2760
2761 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2762 {
2763 debug("unsupported fs:<%s>\n", fs->name);
2764 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2765 goto fail;
2766 }
2767
2768 ventoy_set_env("vtoy_iso_fs", fs->name);
2769
2770 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2771 if (strdata && strdata[0] == '1')
2772 {
2773 g_default_menu_mode = 1;
2774 }
2775
2776 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2777
2778 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2779
2780 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2781 if (strdata && strdata[0] == '/')
2782 {
2783 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2784 if (g_img_iterator_head.dir[len - 1] != '/')
2785 {
2786 g_img_iterator_head.dir[len++] = '/';
2787 }
2788 g_img_iterator_head.dirlen = len;
2789 }
2790 else
2791 {
2792 g_img_iterator_head.dirlen = 1;
2793 grub_strcpy(g_img_iterator_head.dir, "/");
2794 }
2795
2796 g_img_iterator_head.tail = &tail;
2797
2798 if (g_img_max_search_level < 0)
2799 {
2800 g_img_max_search_level = GRUB_INT_MAX;
2801 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2802 if (strdata && ventoy_is_decimal(strdata))
2803 {
2804 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2805 }
2806 }
2807
2808 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2809 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2810 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2811 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2812 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2813 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2814
2815 for (node = &g_img_iterator_head; node; node = node->next)
2816 {
2817 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2818 }
2819
2820 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2821 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2822 {
2823 g_tree_view_menu_style = 1;
2824 }
2825
2826 ventoy_set_default_menu();
2827
2828 for (node = &g_img_iterator_head; node; node = node->next)
2829 {
2830 ventoy_dynamic_tree_menu(node);
2831 }
2832
2833 /* free node */
2834 node = g_img_iterator_head.next;
2835 while (node)
2836 {
2837 tmp = node->next;
2838 grub_free(node);
2839 node = tmp;
2840 }
2841
2842 /* sort image list by image name */
2843 while (g_ventoy_img_list)
2844 {
2845 min = g_ventoy_img_list;
2846 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2847 {
2848 if (ventoy_cmp_img(min, cur) > 0)
2849 {
2850 min = cur;
2851 }
2852 }
2853
2854 if (min->prev)
2855 {
2856 min->prev->next = min->next;
2857 }
2858
2859 if (min->next)
2860 {
2861 min->next->prev = min->prev;
2862 }
2863
2864 if (min == g_ventoy_img_list)
2865 {
2866 g_ventoy_img_list = min->next;
2867 }
2868
2869 if (head == NULL)
2870 {
2871 head = tail = min;
2872 min->prev = NULL;
2873 min->next = NULL;
2874 }
2875 else
2876 {
2877 tail->next = min;
2878 min->prev = tail;
2879 min->next = NULL;
2880 tail = min;
2881 }
2882 }
2883
2884 g_ventoy_img_list = head;
2885
2886 if (g_default_menu_mode == 1)
2887 {
2888 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2889 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2890 " echo 'return ...' \n"
2891 "}\n", "<--");
2892 }
2893
2894 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2895 {
2896 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2897 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2898 " %s_%s \n"
2899 "}\n",
2900 cur->unsupport ? "[***********] " : "",
2901 cur->alias ? cur->alias : cur->name, cur->class, cur,
2902 cur->menu_prefix,
2903 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2904 }
2905
2906 g_tree_script_buf[g_tree_script_pos] = 0;
2907 g_list_script_buf[g_list_script_pos] = 0;
2908
2909 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2910 grub_env_set(args[1], buf);
2911
2912 fail:
2913
2914 check_free(device_name, grub_free);
2915 check_free(dev, grub_device_close);
2916
2917 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2918 }
2919
2920 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2921 {
2922 grub_disk_t disk;
2923 char *device_name;
2924 char *pos;
2925 char *pos2;
2926
2927 device_name = grub_file_get_device_name(filename);
2928 if (!device_name)
2929 {
2930 return 1;
2931 }
2932
2933 pos = device_name;
2934 if (pos[0] == '(')
2935 {
2936 pos++;
2937 }
2938
2939 pos2 = grub_strstr(pos, ",");
2940 if (!pos2)
2941 {
2942 pos2 = grub_strstr(pos, ")");
2943 }
2944
2945 if (pos2)
2946 {
2947 *pos2 = 0;
2948 }
2949
2950 disk = grub_disk_open(pos);
2951 if (disk)
2952 {
2953 grub_disk_read(disk, 0, 0x180, 16, guid);
2954 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2955 grub_disk_close(disk);
2956 }
2957 else
2958 {
2959 return 1;
2960 }
2961
2962 grub_free(device_name);
2963 return 0;
2964 }
2965
2966 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2967 {
2968 eltorito_descriptor desc;
2969
2970 grub_memset(&desc, 0, sizeof(desc));
2971 grub_file_seek(file, 17 * 2048);
2972 grub_file_read(file, &desc, sizeof(desc));
2973
2974 if (desc.type != 0 || desc.version != 1)
2975 {
2976 return 0;
2977 }
2978
2979 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2980 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2981 {
2982 return 0;
2983 }
2984
2985 return desc.sector;
2986 }
2987
2988 static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector)
2989 {
2990 grub_uint8_t buf[512];
2991
2992 grub_file_seek(file, sector * 2048);
2993 grub_file_read(file, buf, sizeof(buf));
2994
2995 if (buf[0] == 0x01 && buf[1] == 0x00 &&
2996 buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88)
2997 {
2998 return *((grub_uint32_t *)(buf + 40));
2999 }
3000
3001 return 0;
3002 }
3003
3004 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
3005 {
3006 int i;
3007 int x86count = 0;
3008 grub_uint8_t buf[512];
3009 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
3010
3011 grub_file_seek(file, sector * 2048);
3012 grub_file_read(file, buf, sizeof(buf));
3013
3014 if (buf[0] == 0x01 && buf[1] == 0xEF)
3015 {
3016 debug("%s efi eltorito in Validation Entry\n", file->name);
3017 return 1;
3018 }
3019
3020 if (buf[0] == 0x01 && buf[1] == 0x00)
3021 {
3022 x86count++;
3023 }
3024
3025 for (i = 64; i < (int)sizeof(buf); i += 32)
3026 {
3027 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
3028 {
3029 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3030 return 1;
3031 }
3032
3033 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
3034 {
3035 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
3036 return 1;
3037 }
3038 }
3039
3040 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
3041 {
3042 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
3043 {
3044 if (buf[36] == parttype[i])
3045 {
3046 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
3047 return 1;
3048 }
3049 }
3050 }
3051
3052 debug("%s does not contain efi eltorito\n", file->name);
3053 return 0;
3054 }
3055
3056 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
3057 {
3058 char *pos;
3059 const char *fs = NULL;
3060 const char *val = NULL;
3061 const char *cdprompt = NULL;
3062 grub_uint32_t i;
3063 grub_uint8_t chksum = 0;
3064 grub_disk_t disk;
3065
3066 disk = file->device->disk;
3067 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
3068
3069 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
3070 param->vtoy_disk_part_id = disk->partition->number + 1;
3071 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
3072
3073 pos = grub_strstr(file->name, "/");
3074 if (!pos)
3075 {
3076 pos = file->name;
3077 }
3078
3079 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
3080
3081 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
3082
3083 param->vtoy_img_size = file->size;
3084
3085 param->vtoy_reserved[0] = g_ventoy_break_level;
3086 param->vtoy_reserved[1] = g_ventoy_debug_level;
3087
3088 param->vtoy_reserved[2] = g_ventoy_chain_type;
3089
3090 /* Windows CD/DVD prompt 0:suppress 1:reserved */
3091 param->vtoy_reserved[4] = 0;
3092 if (g_ventoy_chain_type == 1) /* Windows */
3093 {
3094 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
3095 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
3096 {
3097 param->vtoy_reserved[4] = 1;
3098 }
3099 }
3100
3101 fs = ventoy_get_env("ventoy_fs_probe");
3102 if (fs && grub_strcmp(fs, "udf") == 0)
3103 {
3104 param->vtoy_reserved[3] = 1;
3105 }
3106
3107 param->vtoy_reserved[5] = 0;
3108 val = ventoy_get_env("VTOY_LINUX_REMOUNT");
3109 if (val && val[0] == '1' && val[1] == 0)
3110 {
3111 param->vtoy_reserved[5] = 1;
3112 }
3113
3114 /* ventoy_disk_signature used for vlnk */
3115 param->vtoy_reserved[6] = file->vlnk;
3116 grub_memcpy(param->vtoy_reserved + 7, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4);
3117
3118 /* calculate checksum */
3119 for (i = 0; i < sizeof(ventoy_os_param); i++)
3120 {
3121 chksum += *((grub_uint8_t *)param + i);
3122 }
3123 param->chksum = (grub_uint8_t)(0x100 - chksum);
3124
3125 return;
3126 }
3127
3128 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3129 {
3130 grub_uint32_t i = 0;
3131 grub_uint64_t total = 0;
3132 grub_uint64_t fileblk = 0;
3133 ventoy_img_chunk *chunk = NULL;
3134
3135 for (i = 0; i < chunklist->cur_chunk; i++)
3136 {
3137 chunk = chunklist->chunk + i;
3138
3139 if (chunk->disk_start_sector <= start)
3140 {
3141 debug("%u disk start invalid %lu\n", i, (ulong)start);
3142 return 1;
3143 }
3144
3145 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
3146 }
3147
3148 fileblk = (file->size + 511) / 512;
3149
3150 if (total != fileblk)
3151 {
3152 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
3153 if ((file->size % 512) && (total + 1 == fileblk))
3154 {
3155 debug("maybe img file to be processed.\n");
3156 return 0;
3157 }
3158
3159 return 1;
3160 }
3161
3162 return 0;
3163 }
3164
3165 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
3166 {
3167 int fs_type;
3168 int len;
3169 grub_uint32_t i = 0;
3170 grub_uint32_t sector = 0;
3171 grub_uint32_t count = 0;
3172 grub_off_t size = 0;
3173 grub_off_t read = 0;
3174
3175 fs_type = ventoy_get_fs_type(file->fs->name);
3176 if (fs_type == ventoy_fs_exfat)
3177 {
3178 grub_fat_get_file_chunk(start, file, chunklist);
3179 }
3180 else if (fs_type == ventoy_fs_ext)
3181 {
3182 grub_ext_get_file_chunk(start, file, chunklist);
3183 }
3184 else
3185 {
3186 file->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read;
3187 file->read_hook_data = chunklist;
3188
3189 for (size = file->size; size > 0; size -= read)
3190 {
3191 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
3192 grub_file_read(file, NULL, read);
3193 }
3194
3195 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
3196 {
3197 chunklist->chunk[i].disk_start_sector += start;
3198 chunklist->chunk[i].disk_end_sector += start;
3199 }
3200
3201 if (ventoy_fs_udf == fs_type)
3202 {
3203 for (i = 0; i < chunklist->cur_chunk; i++)
3204 {
3205 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
3206 chunklist->chunk[i].img_start_sector = sector;
3207 chunklist->chunk[i].img_end_sector = sector + count - 1;
3208 sector += count;
3209 }
3210 }
3211 }
3212
3213 len = (int)grub_strlen(file->name);
3214 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
3215 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
3216 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
3217 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
3218 {
3219 for (i = 0; i < chunklist->cur_chunk; i++)
3220 {
3221 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
3222 if (count < 4)
3223 {
3224 count = 1;
3225 }
3226 else
3227 {
3228 count >>= 2;
3229 }
3230
3231 chunklist->chunk[i].img_start_sector = sector;
3232 chunklist->chunk[i].img_end_sector = sector + count - 1;
3233 sector += count;
3234 }
3235 }
3236
3237 return 0;
3238 }
3239
3240 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3241 {
3242 int rc;
3243 grub_file_t file;
3244 grub_disk_addr_t start;
3245
3246 (void)ctxt;
3247 (void)argc;
3248
3249 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3250 if (!file)
3251 {
3252 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3253 }
3254
3255 g_conf_replace_count = 0;
3256 grub_memset(g_conf_replace_node, 0, sizeof(g_conf_replace_node ));
3257 grub_memset(g_conf_replace_offset, 0, sizeof(g_conf_replace_offset ));
3258
3259 if (g_img_chunk_list.chunk)
3260 {
3261 grub_free(g_img_chunk_list.chunk);
3262 }
3263
3264 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
3265 {
3266 grub_file_close(file);
3267 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
3268 }
3269
3270 /* get image chunk data */
3271 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
3272 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3273 if (NULL == g_img_chunk_list.chunk)
3274 {
3275 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3276 }
3277
3278 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
3279 g_img_chunk_list.cur_chunk = 0;
3280
3281 start = file->device->disk->partition->start;
3282
3283 ventoy_get_block_list(file, &g_img_chunk_list, start);
3284
3285 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
3286 grub_file_close(file);
3287
3288 if (rc)
3289 {
3290 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
3291 }
3292
3293 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
3294 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
3295 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3296 }
3297
3298 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
3299 {
3300 int i;
3301 int n;
3302 grub_uint64_t offset = 0;
3303 grub_uint32_t align = 0;
3304 grub_file_t file = NULL;
3305 conf_replace *node = NULL;
3306 conf_replace *nodes[VTOY_MAX_CONF_REPLACE] = { NULL };
3307 ventoy_grub_param_file_replace *replace = NULL;
3308
3309 (void)ctxt;
3310 (void)argc;
3311 (void)args;
3312
3313 debug("select conf replace argc:%d\n", argc);
3314
3315 if (argc < 2)
3316 {
3317 return 0;
3318 }
3319
3320 n = ventoy_plugin_find_conf_replace(args[1], nodes);
3321 if (!n)
3322 {
3323 debug("Conf replace not found for %s\n", args[1]);
3324 goto end;
3325 }
3326
3327 debug("Find %d conf replace for %s\n", n, args[1]);
3328
3329 g_conf_replace_count = n;
3330 for (i = 0; i < n; i++)
3331 {
3332 node = nodes[i];
3333
3334 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3335 if (file)
3336 {
3337 offset = grub_iso9660_get_last_file_dirent_pos(file);
3338 grub_file_close(file);
3339 }
3340 else if (node->img > 0)
3341 {
3342 offset = 0;
3343 }
3344 else
3345 {
3346 debug("<(loop)%s> NOT exist\n", node->orgconf);
3347 continue;
3348 }
3349
3350 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3351 if (!file)
3352 {
3353 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3354 continue;
3355 }
3356
3357 align = ((int)file->size + 2047) / 2048 * 2048;
3358
3359 if (align > vtoy_max_replace_file_size)
3360 {
3361 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3362 grub_file_close(file);
3363 continue;
3364 }
3365
3366 grub_file_read(file, g_conf_replace_new_buf[i], file->size);
3367 grub_file_close(file);
3368 g_conf_replace_new_len[i] = (int)file->size;
3369 g_conf_replace_new_len_align[i] = align;
3370
3371 g_conf_replace_node[i] = node;
3372 g_conf_replace_offset[i] = offset + 2;
3373
3374 if (node->img > 0)
3375 {
3376 replace = &(g_grub_param->img_replace[i]);
3377 replace->magic = GRUB_IMG_REPLACE_MAGIC;
3378 grub_snprintf(replace->old_file_name[replace->old_name_cnt], 256, "%s", node->orgconf);
3379 replace->old_name_cnt++;
3380 }
3381
3382 debug("conf_replace OK: newlen[%d]: %d img:%d\n", i, g_conf_replace_new_len[i], node->img);
3383 }
3384
3385 end:
3386 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3387 }
3388
3389 static int ventoy_var_expand(int *record, int *flag, const char *var, char *expand, int len)
3390 {
3391 int i = 0;
3392 int n = 0;
3393 char c;
3394 const char *ch = var;
3395
3396 *record = 0;
3397 expand[0] = 0;
3398
3399 while (*ch)
3400 {
3401 if (*ch == '_' || (*ch >= '0' && *ch <= '9') || (*ch >= 'A' && *ch <= 'Z') || (*ch >= 'a' && *ch <= 'z'))
3402 {
3403 ch++;
3404 n++;
3405 }
3406 else
3407 {
3408 debug("Invalid variable letter <%c>\n", *ch);
3409 goto end;
3410 }
3411 }
3412
3413 if (n > 32)
3414 {
3415 debug("Invalid variable length:%d <%s>\n", n, var);
3416 goto end;
3417 }
3418
3419 if (grub_strncmp(var, "VT_", 3) == 0) /* built-in variables */
3420 {
3421
3422 }
3423 else
3424 {
3425 if (*flag == 0)
3426 {
3427 *flag = 1;
3428 grub_printf("\n=================== Variables Expansion ===================\n\n");
3429 }
3430
3431 grub_printf("<%s>: ", var);
3432 grub_refresh();
3433
3434 while (i < (len - 1))
3435 {
3436 c = grub_getkey();
3437 if ((c == '\n') || (c == '\r'))
3438 {
3439 if (i > 0)
3440 {
3441 grub_printf("\n");
3442 grub_refresh();
3443 *record = 1;
3444 break;
3445 }
3446 }
3447 else if (grub_isprint(c))
3448 {
3449 if (i + 1 < (len - 1))
3450 {
3451 grub_printf("%c", c);
3452 grub_refresh();
3453 expand[i++] = c;
3454 expand[i] = 0;
3455 }
3456 }
3457 else if (c == '\b')
3458 {
3459 if (i > 0)
3460 {
3461 expand[i - 1] = ' ';
3462 grub_printf("\r<%s>: %s", var, expand);
3463
3464 expand[i - 1] = 0;
3465 grub_printf("\r<%s>: %s", var, expand);
3466
3467 grub_refresh();
3468 i--;
3469 }
3470 }
3471 }
3472 }
3473
3474 end:
3475 if (expand[0] == 0)
3476 {
3477 grub_snprintf(expand, len, "$$%s$$", var);
3478 }
3479
3480 return 0;
3481 }
3482
3483 static int ventoy_auto_install_var_expand(install_template *node)
3484 {
3485 int pos = 0;
3486 int flag = 0;
3487 int record = 0;
3488 int newlen = 0;
3489 char *start = NULL;
3490 char *end = NULL;
3491 char *newbuf = NULL;
3492 char *curline = NULL;
3493 char *nextline = NULL;
3494 grub_uint8_t *code = NULL;
3495 char value[512];
3496 var_node *CurNode = NULL;
3497 var_node *pVarList = NULL;
3498
3499 code = (grub_uint8_t *)node->filebuf;
3500
3501 if (node->filelen >= VTOY_SIZE_1MB)
3502 {
3503 debug("auto install script too long %d\n", node->filelen);
3504 return 0;
3505 }
3506
3507 if ((code[0] == 0xff && code[1] == 0xfe) || (code[0] == 0xfe && code[1] == 0xff))
3508 {
3509 debug("UCS-2 encoding NOT supported\n");
3510 return 0;
3511 }
3512
3513 start = grub_strstr(node->filebuf, "$$");
3514 if (!start)
3515 {
3516 debug("no need to expand variable, no start.\n");
3517 return 0;
3518 }
3519
3520 end = grub_strstr(start + 2, "$$");
3521 if (!end)
3522 {
3523 debug("no need to expand variable, no end.\n");
3524 return 0;
3525 }
3526
3527 newlen = grub_max(node->filelen * 10, VTOY_SIZE_128KB);
3528 newbuf = grub_malloc(newlen);
3529 if (!newbuf)
3530 {
3531 debug("Failed to alloc newbuf %d\n", newlen);
3532 return 0;
3533 }
3534
3535 for (curline = node->filebuf; curline; curline = nextline)
3536 {
3537 nextline = ventoy_get_line(curline);
3538
3539 start = grub_strstr(curline, "$$");
3540 if (start)
3541 {
3542 end = grub_strstr(start + 2, "$$");
3543 }
3544
3545 if (start && end)
3546 {
3547 *start = *end = 0;
3548 VTOY_APPEND_NEWBUF(curline);
3549
3550 for (CurNode = pVarList; CurNode; CurNode = CurNode->next)
3551 {
3552 if (grub_strcmp(start + 2, CurNode->var) == 0)
3553 {
3554 grub_snprintf(value, sizeof(value) - 1, "%s", CurNode->val);
3555 break;
3556 }
3557 }
3558
3559 if (!CurNode)
3560 {
3561 value[sizeof(value) - 1] = 0;
3562 ventoy_var_expand(&record, &flag, start + 2, value, sizeof(value) - 1);
3563
3564 if (record)
3565 {
3566 CurNode = grub_zalloc(sizeof(var_node));
3567 if (CurNode)
3568 {
3569 grub_snprintf(CurNode->var, sizeof(CurNode->var), "%s", start + 2);
3570 grub_snprintf(CurNode->val, sizeof(CurNode->val), "%s", value);
3571 CurNode->next = pVarList;
3572 pVarList = CurNode;
3573 }
3574 }
3575 }
3576
3577 VTOY_APPEND_NEWBUF(value);
3578
3579 VTOY_APPEND_NEWBUF(end + 2);
3580 }
3581 else
3582 {
3583 VTOY_APPEND_NEWBUF(curline);
3584 }
3585
3586 if (pos > 0 && newbuf[pos - 1] == '\r')
3587 {
3588 newbuf[pos - 1] = '\n';
3589 }
3590 else
3591 {
3592 newbuf[pos++] = '\n';
3593 }
3594 }
3595
3596 grub_free(node->filebuf);
3597 node->filebuf = newbuf;
3598 node->filelen = pos;
3599
3600 while (pVarList)
3601 {
3602 CurNode = pVarList->next;
3603 grub_free(pVarList);
3604 pVarList = CurNode;
3605 }
3606
3607 return 0;
3608 }
3609
3610 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3611 {
3612 int i = 0;
3613 int pos = 0;
3614 int defidx = 1;
3615 char *buf = NULL;
3616 grub_file_t file = NULL;
3617 char configfile[128];
3618 install_template *node = NULL;
3619
3620 (void)ctxt;
3621 (void)argc;
3622 (void)args;
3623
3624 debug("select auto installation argc:%d\n", argc);
3625
3626 if (argc < 1)
3627 {
3628 return 0;
3629 }
3630
3631 node = ventoy_plugin_find_install_template(args[0]);
3632 if (!node)
3633 {
3634 debug("Auto install template not found for %s\n", args[0]);
3635 return 0;
3636 }
3637
3638 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3639 {
3640 defidx = node->autosel;
3641 if (node->timeout < 0)
3642 {
3643 node->cursel = node->autosel - 1;
3644 debug("Auto install template auto select %d\n", node->autosel);
3645 return 0;
3646 }
3647 }
3648
3649 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3650 if (!buf)
3651 {
3652 return 0;
3653 }
3654
3655 if (node->timeout > 0)
3656 {
3657 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3658 }
3659
3660 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3661 " echo %s\n}\n", "");
3662
3663 for (i = 0; i < node->templatenum; i++)
3664 {
3665 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\"{\n"
3666 " echo \"\"\n}\n",
3667 node->templatepath[i].path);
3668 }
3669
3670 g_ventoy_menu_esc = 1;
3671 g_ventoy_suppress_esc = 1;
3672 g_ventoy_suppress_esc_default = defidx;
3673
3674 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3675 grub_script_execute_sourcecode(configfile);
3676
3677 g_ventoy_menu_esc = 0;
3678 g_ventoy_suppress_esc = 0;
3679 g_ventoy_suppress_esc_default = 1;
3680
3681 grub_free(buf);
3682
3683 node->cursel = g_ventoy_last_entry - 1;
3684
3685 grub_check_free(node->filebuf);
3686 node->filelen = 0;
3687
3688 if (node->cursel >= 0 && node->cursel < node->templatenum)
3689 {
3690 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"),
3691 node->templatepath[node->cursel].path);
3692 if (file)
3693 {
3694 node->filebuf = grub_malloc(file->size + 8);
3695 if (node->filebuf)
3696 {
3697 grub_file_read(file, node->filebuf, file->size);
3698 grub_file_close(file);
3699
3700 grub_memset(node->filebuf + file->size, 0, 8);
3701 node->filelen = (int)file->size;
3702
3703 ventoy_auto_install_var_expand(node);
3704 }
3705 }
3706 else
3707 {
3708 debug("Failed to open auto install script <%s%s>\n",
3709 ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path);
3710 }
3711 }
3712
3713 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3714 }
3715
3716 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3717 {
3718 int i = 0;
3719 int pos = 0;
3720 int defidx = 1;
3721 char *buf = NULL;
3722 char configfile[128];
3723 persistence_config *node;
3724
3725 (void)ctxt;
3726 (void)argc;
3727 (void)args;
3728
3729 debug("select persistence argc:%d\n", argc);
3730
3731 if (argc < 1)
3732 {
3733 return 0;
3734 }
3735
3736 node = ventoy_plugin_find_persistent(args[0]);
3737 if (!node)
3738 {
3739 debug("Persistence image not found for %s\n", args[0]);
3740 return 0;
3741 }
3742
3743 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3744 {
3745 defidx = node->autosel;
3746 if (node->timeout < 0)
3747 {
3748 node->cursel = node->autosel - 1;
3749 debug("Persistence image auto select %d\n", node->autosel);
3750 return 0;
3751 }
3752 }
3753
3754 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3755 if (!buf)
3756 {
3757 return 0;
3758 }
3759
3760 if (node->timeout > 0)
3761 {
3762 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3763 }
3764
3765 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3766 " echo %s\n}\n", "");
3767
3768 for (i = 0; i < node->backendnum; i++)
3769 {
3770 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3771 " echo \"\"\n}\n",
3772 node->backendpath[i].path);
3773
3774 }
3775
3776 g_ventoy_menu_esc = 1;
3777 g_ventoy_suppress_esc = 1;
3778 g_ventoy_suppress_esc_default = defidx;
3779
3780 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3781 grub_script_execute_sourcecode(configfile);
3782
3783 g_ventoy_menu_esc = 0;
3784 g_ventoy_suppress_esc = 0;
3785 g_ventoy_suppress_esc_default = 1;
3786
3787 grub_free(buf);
3788
3789 node->cursel = g_ventoy_last_entry - 1;
3790
3791 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3792 }
3793
3794 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3795 {
3796 grub_uint32_t i;
3797 ventoy_img_chunk *cur;
3798
3799 (void)ctxt;
3800 (void)argc;
3801 (void)args;
3802
3803 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3804 {
3805 cur = g_img_chunk_list.chunk + i;
3806 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3807 cur->img_start_sector, cur->img_end_sector,
3808 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3809 );
3810 }
3811
3812 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3813 }
3814
3815 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3816 {
3817 grub_uint32_t i;
3818 grub_file_t file;
3819 ventoy_img_chunk_list chunklist;
3820
3821 (void)ctxt;
3822 (void)argc;
3823
3824 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3825 if (!file)
3826 {
3827 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3828 }
3829
3830 /* get image chunk data */
3831 grub_memset(&chunklist, 0, sizeof(chunklist));
3832 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3833 if (NULL == chunklist.chunk)
3834 {
3835 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3836 }
3837
3838 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3839 chunklist.cur_chunk = 0;
3840
3841 ventoy_get_block_list(file, &chunklist, 0);
3842
3843 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3844 {
3845 grub_printf("########## UNSUPPORTED ###############\n");
3846 }
3847
3848 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3849
3850 for (i = 0; i < chunklist.cur_chunk; i++)
3851 {
3852 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3853 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3854 }
3855
3856 grub_printf("\n==================================\n");
3857
3858 for (i = 0; i < chunklist.cur_chunk; i++)
3859 {
3860 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3861 (ulonglong)chunklist.chunk[i].img_start_sector,
3862 (ulonglong)chunklist.chunk[i].img_end_sector,
3863 (ulonglong)chunklist.chunk[i].disk_start_sector,
3864 (ulonglong)chunklist.chunk[i].disk_end_sector
3865 );
3866 }
3867
3868 grub_free(chunklist.chunk);
3869 grub_file_close(file);
3870
3871 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3872 }
3873
3874 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3875 {
3876 int i;
3877 ventoy_grub_param_file_replace *replace = NULL;
3878
3879 (void)ctxt;
3880 (void)argc;
3881 (void)args;
3882
3883 if (argc >= 2)
3884 {
3885 replace = &(g_grub_param->file_replace);
3886 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3887
3888 replace->old_name_cnt = 0;
3889 for (i = 0; i < 4 && i + 1 < argc; i++)
3890 {
3891 replace->old_name_cnt++;
3892 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3893 }
3894
3895 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3896 }
3897
3898 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3899 }
3900
3901 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3902 {
3903 char buf[32];
3904 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3905
3906 (void)ctxt;
3907
3908 if (argc >= 1)
3909 {
3910 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3911 grub_env_set(args[0], buf);
3912 }
3913
3914 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3915 }
3916
3917 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3918 {
3919 (void)ctxt;
3920 (void)argc;
3921 (void)args;
3922
3923 if (argc == 0)
3924 {
3925 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3926 grub_printf("%s", g_list_script_buf);
3927 }
3928 else
3929 {
3930 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3931 grub_printf("%s", g_tree_script_buf);
3932 }
3933
3934 return 0;
3935 }
3936
3937 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3938 {
3939 img_info *cur = g_ventoy_img_list;
3940
3941 (void)ctxt;
3942 (void)argc;
3943 (void)args;
3944
3945 while (cur)
3946 {
3947 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3948 grub_printf("name:<%s>\n\n", cur->name);
3949 cur = cur->next;
3950 }
3951
3952 return 0;
3953 }
3954
3955 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3956 {
3957 (void)ctxt;
3958 (void)argc;
3959 (void)args;
3960
3961 ventoy_plugin_dump_injection();
3962
3963 return 0;
3964 }
3965
3966 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3967 {
3968 (void)ctxt;
3969 (void)argc;
3970 (void)args;
3971
3972 ventoy_plugin_dump_auto_install();
3973
3974 return 0;
3975 }
3976
3977 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3978 {
3979 (void)ctxt;
3980 (void)argc;
3981 (void)args;
3982
3983 ventoy_plugin_dump_persistence();
3984
3985 return 0;
3986 }
3987
3988 static int ventoy_check_mode_by_name(char *filename, const char *suffix)
3989 {
3990 int i;
3991 int len1;
3992 int len2;
3993
3994 len1 = (int)grub_strlen(filename);
3995 len2 = (int)grub_strlen(suffix);
3996
3997 if (len1 <= len2)
3998 {
3999 return 0;
4000 }
4001
4002 for (i = len1 - 1; i >= 0; i--)
4003 {
4004 if (filename[i] == '.')
4005 {
4006 break;
4007 }
4008 }
4009
4010 if (i < len2 + 1)
4011 {
4012 return 0;
4013 }
4014
4015 if (filename[i - len2 - 1] != '_')
4016 {
4017 return 0;
4018 }
4019
4020 if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0)
4021 {
4022 return 1;
4023 }
4024
4025 return 0;
4026 }
4027
4028 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4029 {
4030 (void)ctxt;
4031 (void)argc;
4032 (void)args;
4033
4034 if (argc != 1 && argc != 2)
4035 {
4036 return 1;
4037 }
4038
4039 if (args[0][0] == '0')
4040 {
4041 if (g_ventoy_memdisk_mode)
4042 {
4043 return 0;
4044 }
4045
4046 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk"))
4047 {
4048 return 0;
4049 }
4050
4051 return 1;
4052 }
4053 else if (args[0][0] == '1')
4054 {
4055 return g_ventoy_iso_raw ? 0 : 1;
4056 }
4057 else if (args[0][0] == '2')
4058 {
4059 return g_ventoy_iso_uefi_drv ? 0 : 1;
4060 }
4061 else if (args[0][0] == '3')
4062 {
4063 if (g_ventoy_grub2_mode)
4064 {
4065 return 0;
4066 }
4067
4068 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2"))
4069 {
4070 return 0;
4071 }
4072
4073 return 1;
4074 }
4075 else if (args[0][0] == '4')
4076 {
4077 if (g_ventoy_wimboot_mode)
4078 {
4079 return 0;
4080 }
4081
4082 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot"))
4083 {
4084 return 0;
4085 }
4086
4087 return 1;
4088 }
4089
4090 return 1;
4091 }
4092
4093 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
4094 {
4095 static int configfile_mode = 0;
4096 char memfile[128] = {0};
4097
4098 (void)ctxt;
4099 (void)argc;
4100 (void)args;
4101
4102 /*
4103 * args[0]: 0:normal 1:configfile
4104 * args[1]: 0:list_buf 1:tree_buf
4105 */
4106
4107 if (argc != 2)
4108 {
4109 debug("Invalid argc %d\n", argc);
4110 return 0;
4111 }
4112
4113 VTOY_CMD_CHECK(1);
4114
4115 if (args[0][0] == '0')
4116 {
4117 if (args[1][0] == '0')
4118 {
4119 grub_script_execute_sourcecode(g_list_script_buf);
4120 }
4121 else
4122 {
4123 grub_script_execute_sourcecode(g_tree_script_buf);
4124 }
4125 }
4126 else
4127 {
4128 if (configfile_mode)
4129 {
4130 debug("Now already in F3 mode %d\n", configfile_mode);
4131 return 0;
4132 }
4133
4134 if (args[1][0] == '0')
4135 {
4136 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4137 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
4138 }
4139 else
4140 {
4141 g_ventoy_last_entry = -1;
4142 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4143 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
4144 }
4145
4146 configfile_mode = 1;
4147 grub_script_execute_sourcecode(memfile);
4148 configfile_mode = 0;
4149 }
4150
4151 return 0;
4152 }
4153
4154 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
4155 {
4156 grub_file_t file;
4157
4158 (void)ctxt;
4159
4160 if (argc != 1)
4161 {
4162 return 1;
4163 }
4164
4165 g_ventoy_case_insensitive = 1;
4166 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4167 g_ventoy_case_insensitive = 0;
4168
4169 grub_errno = 0;
4170
4171 if (file)
4172 {
4173 grub_file_close(file);
4174 return 0;
4175 }
4176 return 1;
4177 }
4178
4179 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
4180 {
4181 int id = 0;
4182 int find = 0;
4183 grub_disk_t disk;
4184 const char *isopath = NULL;
4185 char hdname[32];
4186 ventoy_mbr_head mbr;
4187
4188 (void)ctxt;
4189 (void)argc;
4190
4191 if (argc != 1)
4192 {
4193 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
4194 }
4195
4196 isopath = grub_env_get("vtoy_iso_part");
4197 if (!isopath)
4198 {
4199 debug("isopath is null %p\n", isopath);
4200 return 0;
4201 }
4202
4203 debug("isopath is %s\n", isopath);
4204
4205 for (id = 0; id < 30 && (find == 0); id++)
4206 {
4207 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
4208 if (grub_strstr(isopath, hdname))
4209 {
4210 debug("skip %s ...\n", hdname);
4211 continue;
4212 }
4213
4214 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
4215
4216 disk = grub_disk_open(hdname);
4217 if (!disk)
4218 {
4219 debug("%s not exist\n", hdname);
4220 break;
4221 }
4222
4223 grub_memset(&mbr, 0, sizeof(mbr));
4224 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
4225 {
4226 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
4227 {
4228 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
4229 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
4230 {
4231
4232 grub_env_set(args[0], hdname);
4233 find = 1;
4234 }
4235 }
4236 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
4237 }
4238 else
4239 {
4240 debug("read %s failed\n", hdname);
4241 }
4242
4243 grub_disk_close(disk);
4244 }
4245
4246 return 0;
4247 }
4248
4249 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
4250 {
4251 int len = 1024;
4252 grub_file_t file;
4253 char *buf = NULL;
4254
4255 (void)ctxt;
4256 (void)argc;
4257
4258 if (argc != 2)
4259 {
4260 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
4261 }
4262
4263 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4264 if (!file)
4265 {
4266 debug("failed to open file %s\n", args[0]);
4267 return 0;
4268 }
4269
4270 buf = grub_malloc(len);
4271 if (!buf)
4272 {
4273 goto end;
4274 }
4275
4276 buf[len - 1] = 0;
4277 grub_file_read(file, buf, len - 1);
4278
4279 ventoy_get_line(buf);
4280 ventoy_set_env(args[1], buf);
4281
4282 end:
4283
4284 grub_check_free(buf);
4285 grub_file_close(file);
4286
4287 return 0;
4288 }
4289
4290 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
4291 {
4292 grub_uint64_t end_max = 0;
4293 int *pCnt = (int *)data;
4294
4295 (void)disk;
4296
4297 (*pCnt)++;
4298 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
4299 "0 %llu linear /dev/ventoy %llu\n",
4300 (ulonglong)partition->len, (ulonglong)partition->start);
4301
4302 end_max = (partition->len + partition->start) * 512;
4303 if (end_max > g_part_end_max)
4304 {
4305 g_part_end_max = end_max;
4306 }
4307
4308 return 0;
4309 }
4310
4311 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
4312 {
4313 int cnt = 0;
4314 char *device_name = NULL;
4315 grub_device_t dev = NULL;
4316 char buf[64];
4317
4318 (void)ctxt;
4319
4320 g_part_list_pos = 0;
4321 g_part_end_max = 0;
4322 grub_env_unset("vtoy_img_part_file");
4323
4324 if (argc != 1)
4325 {
4326 return 1;
4327 }
4328
4329 device_name = grub_file_get_device_name(args[0]);
4330 if (!device_name)
4331 {
4332 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
4333 goto end;
4334 }
4335
4336 dev = grub_device_open(device_name);
4337 if (!dev)
4338 {
4339 debug("grub_device_open failed, %s\n", device_name);
4340 goto end;
4341 }
4342
4343 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
4344
4345 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
4346 grub_env_set("vtoy_img_part_file", buf);
4347
4348 grub_snprintf(buf, sizeof(buf), "%d", cnt);
4349 grub_env_set("vtoy_img_part_cnt", buf);
4350
4351 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max);
4352 grub_env_set("vtoy_img_max_part_end", buf);
4353
4354 end:
4355
4356 check_free(device_name, grub_free);
4357 check_free(dev, grub_device_close);
4358
4359 return 0;
4360 }
4361
4362
4363 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
4364 {
4365 int rc = 1;
4366 grub_file_t file;
4367 char *buf = NULL;
4368
4369 (void)ctxt;
4370 (void)argc;
4371
4372 if (argc != 2)
4373 {
4374 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
4375 }
4376
4377 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4378 if (!file)
4379 {
4380 debug("failed to open file %s\n", args[0]);
4381 return 1;
4382 }
4383
4384 buf = grub_malloc(file->size + 1);
4385 if (!buf)
4386 {
4387 goto end;
4388 }
4389
4390 buf[file->size] = 0;
4391 grub_file_read(file, buf, file->size);
4392
4393 if (grub_strstr(buf, args[1]))
4394 {
4395 rc = 0;
4396 }
4397
4398 end:
4399
4400 grub_check_free(buf);
4401 grub_file_close(file);
4402
4403 return rc;
4404 }
4405
4406 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
4407 {
4408 int len;
4409 grub_file_t file;
4410 char buf[64];
4411 grub_uint64_t size;
4412 ventoy_iso9660_vd pvd;
4413
4414 (void)ctxt;
4415 (void)argc;
4416
4417 if (argc != 4)
4418 {
4419 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
4420 }
4421
4422 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4423 if (!file)
4424 {
4425 debug("failed to open file %s\n", args[0]);
4426 return 0;
4427 }
4428
4429 grub_file_seek(file, 16 * 2048);
4430 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
4431 if (len != sizeof(pvd))
4432 {
4433 debug("failed to read pvd %d\n", len);
4434 goto end;
4435 }
4436
4437 grub_memset(buf, 0, sizeof(buf));
4438 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
4439 ventoy_set_env(args[1], buf);
4440
4441 grub_memset(buf, 0, sizeof(buf));
4442 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
4443 ventoy_set_env(args[2], buf);
4444
4445 size = pvd.space;
4446 size *= 2048;
4447 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
4448 ventoy_set_env(args[3], buf);
4449
4450 end:
4451 grub_file_close(file);
4452
4453 return 0;
4454 }
4455
4456 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
4457 {
4458 int len;
4459 grub_file_t file;
4460 char buf[64];
4461
4462 (void)ctxt;
4463 (void)argc;
4464
4465 if (argc != 2)
4466 {
4467 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
4468 }
4469
4470 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4471 if (!file)
4472 {
4473 debug("failed to open file %s\n", args[0]);
4474 return 0;
4475 }
4476
4477 grub_memset(buf, 0, sizeof(buf));
4478 grub_file_seek(file, 16 * 2048 + 813);
4479 len = (int)grub_file_read(file, buf, 17);
4480 if (len != 17)
4481 {
4482 debug("failed to read create date %d\n", len);
4483 goto end;
4484 }
4485
4486 ventoy_set_env(args[1], buf);
4487
4488 end:
4489 grub_file_close(file);
4490
4491 return 0;
4492 }
4493
4494 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4495 {
4496 (void)ctxt;
4497 (void)argc;
4498 (void)args;
4499
4500 ventoy_env_hook_root(1);
4501
4502 return 0;
4503 }
4504
4505 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4506 {
4507 (void)ctxt;
4508 (void)argc;
4509 (void)args;
4510
4511 ventoy_env_hook_root(0);
4512
4513 return 0;
4514 }
4515
4516 #ifdef GRUB_MACHINE_EFI
4517 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4518 {
4519 int ret = 1;
4520 grub_uint8_t *var;
4521 grub_size_t size;
4522 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4523
4524 (void)ctxt;
4525 (void)argc;
4526 (void)args;
4527
4528 var = grub_efi_get_variable("SecureBoot", &global, &size);
4529 if (var && *var == 1)
4530 {
4531 return 0;
4532 }
4533
4534 return ret;
4535 }
4536 #else
4537 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4538 {
4539 (void)ctxt;
4540 (void)argc;
4541 (void)args;
4542 return 1;
4543 }
4544 #endif
4545
4546 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
4547 {
4548 int i;
4549 int ret = 1;
4550 grub_file_t file;
4551 grub_uint64_t FileSectors = 0;
4552 ventoy_gpt_info *gpt = NULL;
4553 ventoy_part_table *pt = NULL;
4554 grub_uint8_t zeroguid[16] = {0};
4555
4556 (void)ctxt;
4557 (void)argc;
4558
4559 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4560 if (!file)
4561 {
4562 debug("failed to open file %s\n", args[0]);
4563 return 1;
4564 }
4565
4566 if (file->size % 512)
4567 {
4568 debug("unaligned file size: %llu\n", (ulonglong)file->size);
4569 goto out;
4570 }
4571
4572 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
4573 if (!gpt)
4574 {
4575 goto out;
4576 }
4577
4578 FileSectors = file->size / 512;
4579
4580 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
4581 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
4582 {
4583 debug("This is EFI partition table\n");
4584
4585 for (i = 0; i < 128; i++)
4586 {
4587 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
4588 {
4589 if (FileSectors < gpt->PartTbl[i].LastLBA)
4590 {
4591 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4592 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
4593 goto out;
4594 }
4595 }
4596 }
4597 }
4598 else
4599 {
4600 debug("This is MBR partition table\n");
4601
4602 for (i = 0; i < 4; i++)
4603 {
4604 pt = gpt->MBR.PartTbl + i;
4605 if (FileSectors < pt->StartSectorId + pt->SectorCount)
4606 {
4607 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4608 (ulonglong)(pt->StartSectorId + pt->SectorCount),
4609 (ulonglong)FileSectors);
4610 goto out;
4611 }
4612 }
4613 }
4614
4615 ret = 0;
4616
4617 out:
4618 grub_file_close(file);
4619 grub_check_free(gpt);
4620 grub_errno = GRUB_ERR_NONE;
4621 return ret;
4622 }
4623
4624 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
4625 {
4626 int i;
4627 int ret;
4628
4629 (void)ctxt;
4630 (void)argc;
4631 (void)args;
4632
4633 for (i = 0; i < 500; i++)
4634 {
4635 ret = grub_getkey_noblock();
4636 if (ret == GRUB_TERM_NO_KEY)
4637 {
4638 break;
4639 }
4640 }
4641
4642 if (i >= 500)
4643 {
4644 grub_cls();
4645 grub_printf("\n\n Still have key input after clear.\n");
4646 grub_refresh();
4647 grub_sleep(5);
4648 }
4649
4650 return 0;
4651 }
4652
4653 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4654 {
4655 int i;
4656 int buflen;
4657 int datalen;
4658 int loclen;
4659 int img_chunk_num;
4660 int image_sector_size;
4661 char cmd[64];
4662 ventoy_chain_head *chain;
4663 ventoy_img_chunk *chunk;
4664 ventoy_os_param *osparam;
4665 ventoy_image_location *location;
4666 ventoy_image_disk_region *region;
4667 struct grub_acpi_table_header *acpi;
4668
4669 (void)ctxt;
4670
4671 if (argc != 2)
4672 {
4673 return 1;
4674 }
4675
4676 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4677
4678 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4679 if (!chain)
4680 {
4681 return 1;
4682 }
4683
4684 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4685
4686 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4687 {
4688 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4689 return 1;
4690 }
4691
4692 img_chunk_num = chain->img_chunk_num;
4693
4694 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4695 datalen = sizeof(ventoy_os_param) + loclen;
4696
4697 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4698 acpi = grub_zalloc(buflen);
4699 if (!acpi)
4700 {
4701 return 1;
4702 }
4703
4704 /* Step1: Fill acpi table header */
4705 grub_memcpy(acpi->signature, "VTOY", 4);
4706 acpi->length = buflen;
4707 acpi->revision = 1;
4708 grub_memcpy(acpi->oemid, "VENTOY", 6);
4709 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4710 acpi->oemrev = 1;
4711 acpi->creator_id[0] = 1;
4712 acpi->creator_rev = 1;
4713
4714 /* Step2: Fill data */
4715 osparam = (ventoy_os_param *)(acpi + 1);
4716 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4717 osparam->vtoy_img_location_addr = 0;
4718 osparam->vtoy_img_location_len = loclen;
4719 osparam->chksum = 0;
4720 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4721
4722 location = (ventoy_image_location *)(osparam + 1);
4723 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4724 location->image_sector_size = image_sector_size;
4725 location->disk_sector_size = chain->disk_sector_size;
4726 location->region_count = img_chunk_num;
4727
4728 region = location->regions;
4729 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4730 if (512 == image_sector_size)
4731 {
4732 for (i = 0; i < img_chunk_num; i++)
4733 {
4734 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4735 region->image_start_sector = chunk->img_start_sector * 4;
4736 region->disk_start_sector = chunk->disk_start_sector;
4737 region++;
4738 chunk++;
4739 }
4740 }
4741 else
4742 {
4743 for (i = 0; i < img_chunk_num; i++)
4744 {
4745 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4746 region->image_start_sector = chunk->img_start_sector;
4747 region->disk_start_sector = chunk->disk_start_sector;
4748 region++;
4749 chunk++;
4750 }
4751 }
4752
4753 /* Step3: Fill acpi checksum */
4754 acpi->checksum = 0;
4755 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4756
4757 /* load acpi table */
4758 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4759 grub_script_execute_sourcecode(cmd);
4760
4761 grub_free(acpi);
4762
4763 VENTOY_CMD_RETURN(0);
4764 }
4765
4766 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4767 {
4768 (void)ctxt;
4769 (void)argc;
4770 (void)args;
4771
4772 g_ventoy_last_entry_back = g_ventoy_last_entry;
4773 g_ventoy_last_entry = -1;
4774
4775 return 0;
4776 }
4777
4778 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4779 {
4780 (void)ctxt;
4781 (void)argc;
4782 (void)args;
4783
4784 g_ventoy_last_entry = g_ventoy_last_entry_back;
4785
4786 return 0;
4787 }
4788
4789 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4790 {
4791 const char *pos = filename + 1;
4792
4793 if (info->dir)
4794 {
4795 while (*pos)
4796 {
4797 if (*pos == '.')
4798 {
4799 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4800 {
4801 grub_strncpy((char *)data, filename, 128);
4802 return 1;
4803 }
4804 }
4805 pos++;
4806 }
4807 }
4808
4809 return 0;
4810 }
4811
4812 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4813 {
4814 int rc = 1;
4815 char *device_name = NULL;
4816 grub_device_t dev = NULL;
4817 grub_fs_t fs = NULL;
4818 char buf[128] = {0};
4819
4820 (void)ctxt;
4821
4822 if (argc != 3)
4823 {
4824 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4825 return 1;
4826 }
4827
4828 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4829
4830 device_name = grub_file_get_device_name(args[0]);
4831 if (!device_name)
4832 {
4833 debug("grub_file_get_device_name failed, %s\n", args[0]);
4834 goto end;
4835 }
4836
4837 dev = grub_device_open(device_name);
4838 if (!dev)
4839 {
4840 debug("grub_device_open failed, %s\n", device_name);
4841 goto end;
4842 }
4843
4844 fs = grub_fs_probe(dev);
4845 if (!fs)
4846 {
4847 debug("grub_fs_probe failed, %s\n", device_name);
4848 goto end;
4849 }
4850
4851 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4852
4853 if (buf[0])
4854 {
4855 ventoy_set_env(args[2], buf);
4856 }
4857
4858 rc = 0;
4859
4860 end:
4861
4862 check_free(device_name, grub_free);
4863 check_free(dev, grub_device_close);
4864
4865 return rc;
4866 }
4867
4868 int ventoy_load_part_table(const char *diskname)
4869 {
4870 char name[64];
4871 int ret;
4872 grub_disk_t disk;
4873 grub_device_t dev;
4874
4875 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4876 if (!g_ventoy_part_info)
4877 {
4878 return 1;
4879 }
4880
4881 disk = grub_disk_open(diskname);
4882 if (!disk)
4883 {
4884 debug("Failed to open disk %s\n", diskname);
4885 return 1;
4886 }
4887
4888 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4889
4890 g_ventoy_disk_bios_id = disk->id;
4891
4892 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4893 grub_disk_close(disk);
4894
4895 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4896 dev = grub_device_open(name);
4897 if (dev)
4898 {
4899 /* Check for official Ventoy device */
4900 ret = ventoy_check_official_device(dev);
4901 grub_device_close(dev);
4902
4903 if (ret)
4904 {
4905 return 1;
4906 }
4907 }
4908
4909 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4910 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4911
4912 return 0;
4913 }
4914
4915 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4916 {
4917 int ret;
4918
4919 (void)argc;
4920 (void)ctxt;
4921
4922 ret = ventoy_load_part_table(args[0]);
4923 if (ret)
4924 {
4925 grub_exit();
4926 }
4927
4928 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4929 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4930
4931 return 0;
4932 }
4933
4934 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4935 {
4936 int ret = 1;
4937 const char *vcfg = NULL;
4938
4939 (void)argc;
4940 (void)ctxt;
4941
4942 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4943 if (vcfg)
4944 {
4945 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4946 grub_env_set(args[1], vcfg);
4947 ret = 0;
4948 }
4949 else
4950 {
4951 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4952 }
4953
4954 grub_errno = 0;
4955 return ret;
4956 }
4957
4958
4959 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4960 {
4961 int id;
4962 grub_uint8_t zeroguid[16] = {0};
4963
4964 (void)argc;
4965 (void)ctxt;
4966
4967 id = (int)grub_strtoul(args[0], NULL, 10);
4968 grub_errno = 0;
4969
4970 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4971 {
4972 if (id >= 1 && id <= 128)
4973 {
4974 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4975 {
4976 return 0;
4977 }
4978 }
4979 }
4980 else
4981 {
4982 if (id >= 1 && id <= 4)
4983 {
4984 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4985 {
4986 return 0;
4987 }
4988 }
4989 }
4990
4991 return 1;
4992 }
4993
4994 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4995 {
4996 int rc = 1;
4997 char *device_name = NULL;
4998 grub_device_t dev = NULL;
4999 grub_fs_t fs = NULL;
5000 char *label = NULL;
5001
5002 (void)ctxt;
5003
5004 debug("get fs label for %s\n", args[0]);
5005
5006 if (argc != 2)
5007 {
5008 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
5009 return 1;
5010 }
5011
5012 device_name = grub_file_get_device_name(args[0]);
5013 if (!device_name)
5014 {
5015 debug("grub_file_get_device_name failed, %s\n", args[0]);
5016 goto end;
5017 }
5018
5019 dev = grub_device_open(device_name);
5020 if (!dev)
5021 {
5022 debug("grub_device_open failed, %s\n", device_name);
5023 goto end;
5024 }
5025
5026 fs = grub_fs_probe(dev);
5027 if (NULL == fs || NULL == fs->fs_label)
5028 {
5029 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
5030 goto end;
5031 }
5032
5033 fs->fs_label(dev, &label);
5034 if (label)
5035 {
5036 debug("label=<%s>\n", label);
5037 ventoy_set_env(args[1], label);
5038 grub_free(label);
5039 }
5040
5041 rc = 0;
5042
5043 end:
5044
5045 check_free(device_name, grub_free);
5046 check_free(dev, grub_device_close);
5047
5048 return rc;
5049 }
5050
5051 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5052 {
5053 if (!info->dir)
5054 {
5055 grub_snprintf((char *)data, 256, "%s", filename);
5056 return 1;
5057 }
5058
5059 return 0;
5060 }
5061
5062 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5063 {
5064 if (info->dir && filename && filename[0] != '.')
5065 {
5066 grub_snprintf((char *)data, 256, "%s", filename);
5067 return 1;
5068 }
5069
5070 return 0;
5071 }
5072
5073 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
5074 {
5075 int rc = 1;
5076 char *device_name = NULL;
5077 grub_device_t dev = NULL;
5078 grub_fs_t fs = NULL;
5079 char name[256] ={0};
5080
5081 if (argc != 3)
5082 {
5083 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
5084 return 1;
5085 }
5086
5087 device_name = grub_file_get_device_name(args[0]);
5088 if (!device_name)
5089 {
5090 debug("grub_file_get_device_name failed, %s\n", args[0]);
5091 goto end;
5092 }
5093
5094 dev = grub_device_open(device_name);
5095 if (!dev)
5096 {
5097 debug("grub_device_open failed, %s\n", device_name);
5098 goto end;
5099 }
5100
5101 fs = grub_fs_probe(dev);
5102 if (!fs)
5103 {
5104 debug("grub_fs_probe failed, %s\n", device_name);
5105 goto end;
5106 }
5107
5108 fs->fs_dir(dev, args[1], hook, name);
5109 if (name[0])
5110 {
5111 ventoy_set_env(args[2], name);
5112 }
5113
5114 rc = 0;
5115
5116 end:
5117
5118 check_free(device_name, grub_free);
5119 check_free(dev, grub_device_close);
5120
5121 return rc;
5122 }
5123
5124 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
5125 {
5126 (void)ctxt;
5127 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
5128 }
5129
5130 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
5131 {
5132 (void)ctxt;
5133 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
5134 }
5135
5136 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
5137 {
5138 char c;
5139 char *pos = NULL;
5140 char *end = NULL;
5141
5142 (void)ctxt;
5143
5144 if (argc != 2)
5145 {
5146 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
5147 return 1;
5148 }
5149
5150 for (pos = args[0]; *pos; pos++)
5151 {
5152 if (*pos == '.')
5153 {
5154 end = pos;
5155 }
5156 }
5157
5158 if (end)
5159 {
5160 c = *end;
5161 *end = 0;
5162 }
5163
5164 grub_env_set(args[1], args[0]);
5165
5166 if (end)
5167 {
5168 *end = c;
5169 }
5170
5171 return 0;
5172 }
5173
5174 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
5175 {
5176 int i;
5177 int len;
5178 const char *buf;
5179
5180 (void)ctxt;
5181
5182 if (argc != 2)
5183 {
5184 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
5185 return 1;
5186 }
5187
5188 buf = args[0];
5189 len = (int)grub_strlen(buf);
5190 for (i = len; i > 0; i--)
5191 {
5192 if (buf[i - 1] == '/')
5193 {
5194 grub_env_set(args[1], buf + i);
5195 return 0;
5196 }
5197 }
5198
5199 grub_env_set(args[1], buf);
5200
5201 return 0;
5202 }
5203
5204 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5205 {
5206 struct grub_video_mode_info info;
5207 char buf[32];
5208
5209 (void)ctxt;
5210 (void)argc;
5211 (void)args;
5212
5213 if (!g_video_mode_list)
5214 {
5215 ventoy_enum_video_mode();
5216 }
5217
5218 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5219 {
5220 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
5221 }
5222 else
5223 {
5224 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
5225 }
5226
5227 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
5228
5229 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
5230 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
5231
5232 VENTOY_CMD_RETURN(0);
5233 }
5234
5235 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5236 {
5237 struct grub_video_mode_info info;
5238 char buf[32];
5239
5240 (void)ctxt;
5241 (void)argc;
5242 (void)args;
5243
5244 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5245 {
5246 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
5247 }
5248 else
5249 {
5250 grub_snprintf(buf, sizeof(buf), "0x0x0");
5251 }
5252
5253 grub_env_set(args[0], buf);
5254
5255 VENTOY_CMD_RETURN(0);
5256 }
5257
5258 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5259 {
5260 int id;
5261 char buf[32];
5262
5263 (void)ctxt;
5264 (void)argc;
5265
5266 if (!g_video_mode_list)
5267 {
5268 return 0;
5269 }
5270
5271 id = (int)grub_strtoul(args[0], NULL, 10);
5272 if (id < g_video_mode_num)
5273 {
5274 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5275 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5276 }
5277
5278 grub_env_set(args[1], buf);
5279
5280 VENTOY_CMD_RETURN(0);
5281 }
5282
5283 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5284 {
5285 grub_uint32_t i;
5286 grub_uint32_t loadsector = 0;
5287 grub_file_t file;
5288 char value[32];
5289 grub_uint32_t boot_catlog = 0;
5290 grub_uint8_t buf[512];
5291
5292 (void)ctxt;
5293
5294 if (argc != 2)
5295 {
5296 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5297 return 1;
5298 }
5299
5300 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5301 if (!file)
5302 {
5303 debug("failed to open %s\n", args[0]);
5304 return 1;
5305 }
5306
5307 boot_catlog = ventoy_get_iso_boot_catlog(file);
5308 if (boot_catlog == 0)
5309 {
5310 debug("No bootcatlog found\n");
5311 grub_file_close(file);
5312 return 1;
5313 }
5314
5315 grub_memset(buf, 0, sizeof(buf));
5316 grub_file_seek(file, boot_catlog * 2048);
5317 grub_file_read(file, buf, sizeof(buf));
5318 grub_file_close(file);
5319
5320 for (i = 0; i < sizeof(buf); i += 32)
5321 {
5322 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5323 {
5324 if (buf[i + 32] == 0x88)
5325 {
5326 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5327 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5328 break;
5329 }
5330 }
5331 }
5332
5333 if (loadsector == 0)
5334 {
5335 debug("No EFI eltorito info found\n");
5336 return 1;
5337 }
5338
5339 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5340 grub_env_set(args[1], value);
5341 VENTOY_CMD_RETURN(0);
5342 }
5343
5344 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5345 {
5346 int curpos;
5347 int printlen;
5348 grub_size_t len;
5349 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5350
5351 if (pfsdir->initrd[0])
5352 {
5353 return 1;
5354 }
5355
5356 curpos = pfsdir->curpos;
5357 len = grub_strlen(filename);
5358
5359 if (info->dir)
5360 {
5361 if ((len == 1 && filename[0] == '.') ||
5362 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5363 {
5364 return 0;
5365 }
5366
5367 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5368 pfsdir->dircnt++;
5369
5370 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5371 pfsdir->curpos = curpos + printlen;
5372 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5373 pfsdir->curpos = curpos;
5374 pfsdir->fullpath[curpos] = 0;
5375 }
5376 else
5377 {
5378 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5379 pfsdir->filecnt++;
5380
5381 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5382 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5383 {
5384 if (info->size > 32 * VTOY_SIZE_1MB)
5385 {
5386 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5387 return 1;
5388 }
5389 }
5390 }
5391
5392 return 0;
5393 }
5394
5395 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5396 {
5397 int i;
5398 char *pos = NULL;
5399 char *device_name = NULL;
5400 grub_device_t dev = NULL;
5401 grub_fs_t fs = NULL;
5402 replace_fs_dir *pfsdir = NULL;
5403
5404 (void)ctxt;
5405
5406 if (argc != 2)
5407 {
5408 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5409 return 1;
5410 }
5411
5412 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5413 if (!pfsdir)
5414 {
5415 return 1;
5416 }
5417
5418 device_name = grub_file_get_device_name(args[0]);
5419 if (!device_name)
5420 {
5421 goto fail;
5422 }
5423
5424 dev = grub_device_open(device_name);
5425 if (!dev)
5426 {
5427 goto fail;
5428 }
5429
5430 fs = grub_fs_probe(dev);
5431 if (!fs)
5432 {
5433 goto fail;
5434 }
5435
5436 pfsdir->dev = dev;
5437 pfsdir->fs = fs;
5438 pfsdir->curpos = 1;
5439 pfsdir->fullpath[0] = '/';
5440 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5441
5442 if (pfsdir->initrd[0])
5443 {
5444 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5445
5446 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5447 {
5448 if (pfsdir->initrd[i] == '/')
5449 {
5450 pfsdir->initrd[i] = '\\';
5451 }
5452 }
5453
5454 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5455 grub_env_set(args[1], pos);
5456 }
5457 else
5458 {
5459 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5460 }
5461
5462 fail:
5463
5464 grub_check_free(pfsdir);
5465 grub_check_free(device_name);
5466 check_free(dev, grub_device_close);
5467
5468 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5469 }
5470
5471 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5472 {
5473 const char *pager = NULL;
5474
5475 (void)ctxt;
5476 (void)argc;
5477 (void)args;
5478
5479 pager = grub_env_get("pager");
5480 if (NULL == pager)
5481 {
5482 g_pager_flag = 1;
5483 grub_env_set("pager", "1");
5484 }
5485 else if (pager[0] == '1')
5486 {
5487 g_pager_flag = 0;
5488 }
5489 else
5490 {
5491 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5492 g_pager_flag = 2;
5493 grub_env_set("pager", "1");
5494 }
5495
5496 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5497 }
5498
5499 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5500 {
5501 (void)ctxt;
5502 (void)argc;
5503 (void)args;
5504
5505 if (g_pager_flag == 1)
5506 {
5507 grub_env_unset("pager");
5508 }
5509 else if (g_pager_flag == 2)
5510 {
5511 grub_env_set("pager", g_old_pager);
5512 }
5513
5514 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5515 }
5516
5517 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5518 {
5519 if (g_json_case_mis_path[0])
5520 {
5521 return 1;
5522 }
5523
5524 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5525 {
5526 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5527 return 1;
5528 }
5529 return 0;
5530 }
5531
5532 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5533 {
5534 char path[16];
5535 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5536
5537 if (g_json_case_mis_path[0])
5538 {
5539 return 1;
5540 }
5541
5542 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5543 {
5544 if (grub_strcasecmp(filename, "ventoy") == 0)
5545 {
5546 grub_snprintf(path, sizeof(path), "/%s", filename);
5547 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5548 if (g_json_case_mis_path[0])
5549 {
5550 return 1;
5551 }
5552 }
5553 }
5554
5555 return 0;
5556 }
5557
5558 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5559 {
5560 int fstype = 0;
5561 char *device_name = NULL;
5562 grub_device_t dev = NULL;
5563 grub_fs_t fs = NULL;
5564 chk_case_fs_dir fs_dir;
5565
5566 (void)ctxt;
5567 (void)argc;
5568 (void)args;
5569
5570 device_name = grub_file_get_device_name(args[0]);
5571 if (!device_name)
5572 {
5573 goto out;
5574 }
5575
5576 dev = grub_device_open(device_name);
5577 if (!dev)
5578 {
5579 goto out;
5580 }
5581
5582 fs = grub_fs_probe(dev);
5583 if (!fs)
5584 {
5585 goto out;
5586 }
5587
5588 fstype = ventoy_get_fs_type(fs->name);
5589 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5590 {
5591 goto out;
5592 }
5593
5594 g_json_case_mis_path[0] = 0;
5595 fs_dir.dev = dev;
5596 fs_dir.fs = fs;
5597 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5598
5599 if (g_json_case_mis_path[0])
5600 {
5601 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5602 }
5603
5604 out:
5605
5606 grub_check_free(device_name);
5607 check_free(dev, grub_device_close);
5608
5609 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5610 }
5611
5612 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5613 {
5614 grub_disk_t disk;
5615 grub_partition_t part;
5616 char priority_str[3]; /* Maximum value 15 */
5617
5618 (void)ctxt;
5619
5620 if (argc < 2 || argc > 3)
5621 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5622 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5623
5624 /* Open the disk if it exists */
5625 disk = grub_disk_open (args[0]);
5626 if (!disk)
5627 {
5628 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5629 "Not a disk");
5630 }
5631
5632 part = grub_partition_probe (disk, args[1]);
5633 if (!part)
5634 {
5635 grub_disk_close (disk);
5636 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5637 "No such partition");
5638 }
5639
5640 if (grub_strcmp (part->partmap->name, "gpt"))
5641 {
5642 grub_disk_close (disk);
5643 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5644 "Not a GPT partition");
5645 }
5646
5647 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5648 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5649
5650 if (argc == 3)
5651 {
5652 grub_env_set (args[2], priority_str);
5653 grub_env_export (args[2]);
5654 }
5655 else
5656 {
5657 grub_printf ("Priority is %s\n", priority_str);
5658 }
5659
5660 grub_disk_close (disk);
5661 return GRUB_ERR_NONE;
5662 }
5663
5664
5665 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5666 {
5667 int ret = 1;
5668 int joliet = 0;
5669 grub_file_t file = NULL;
5670 grub_uint32_t loadrba = 0;
5671 grub_uint32_t boot_catlog = 0;
5672 grub_uint8_t sector[512];
5673 boot_info_table *info = NULL;
5674
5675 (void)ctxt;
5676 (void)argc;
5677
5678 /* This also trigger a iso9660 fs parse */
5679 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5680 {
5681 return 0;
5682 }
5683
5684 joliet = grub_iso9660_is_joliet();
5685 if (joliet == 0)
5686 {
5687 return 1;
5688 }
5689
5690 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5691 if (!file)
5692 {
5693 debug("failed to open %s\n", args[0]);
5694 return 1;
5695 }
5696
5697 boot_catlog = ventoy_get_iso_boot_catlog(file);
5698 if (boot_catlog == 0)
5699 {
5700 debug("no bootcatlog found %u\n", boot_catlog);
5701 goto out;
5702 }
5703
5704 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5705 if (loadrba == 0)
5706 {
5707 debug("no bios eltorito rba found %u\n", loadrba);
5708 goto out;
5709 }
5710
5711 grub_file_seek(file, loadrba * 2048);
5712 grub_file_read(file, sector, 512);
5713
5714 info = (boot_info_table *)sector;
5715 if (info->bi_data0 == 0x7c6ceafa &&
5716 info->bi_data1 == 0x90900000 &&
5717 info->bi_PrimaryVolumeDescriptor == 16 &&
5718 info->bi_BootFileLocation == loadrba)
5719 {
5720 debug("bootloader is syslinux, %u.\n", loadrba);
5721 ret = 0;
5722 }
5723
5724 out:
5725
5726 grub_file_close(file);
5727 grub_errno = GRUB_ERR_NONE;
5728 return ret;
5729 }
5730
5731 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5732 {
5733 int n = 0;
5734 ventoy_vlnk_part *node;
5735
5736 (void)ctxt;
5737 (void)argc;
5738 (void)args;
5739
5740 for (node = g_vlnk_part_list; node; node = node->next)
5741 {
5742 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5743 ++n, node->device, node->disksig,
5744 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5745 }
5746
5747 return 0;
5748 }
5749
5750 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5751 {
5752 int len = 0;
5753
5754 (void)ctxt;
5755
5756 if (argc == 1)
5757 {
5758 len = (int)grub_strlen(args[0]);
5759 if (grub_file_is_vlnk_suffix(args[0], len))
5760 {
5761 return 0;
5762 }
5763 }
5764
5765 return 1;
5766 }
5767
5768 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5769 {
5770 int vlnk = 0;
5771 const char *name = NULL;
5772
5773 (void)ctxt;
5774
5775 if (argc == 2)
5776 {
5777 grub_env_unset(args[1]);
5778 name = grub_file_get_vlnk(args[0], &vlnk);
5779 if (vlnk)
5780 {
5781 debug("VLNK SRC: <%s>\n", args[0]);
5782 debug("VLNK DST: <%s>\n", name);
5783 grub_env_set(args[1], name);
5784 return 0;
5785 }
5786 }
5787
5788 return 1;
5789 }
5790
5791 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5792 {
5793 int ret = 1;
5794 int len = 0;
5795 grub_file_t file = NULL;
5796 ventoy_vlnk vlnk;
5797 char dst[512];
5798
5799 (void)ctxt;
5800
5801 if (argc != 1)
5802 {
5803 goto out;
5804 }
5805
5806 len = (int)grub_strlen(args[0]);
5807 if (!grub_file_is_vlnk_suffix(args[0], len))
5808 {
5809 grub_printf("Invalid vlnk suffix\n");
5810 goto out;
5811 }
5812
5813 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5814 if (!file)
5815 {
5816 grub_printf("Failed to open %s\n", args[0]);
5817 goto out;
5818 }
5819
5820 if (file->size != 32768)
5821 {
5822 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5823 goto out;
5824 }
5825
5826 grub_memset(&vlnk, 0, sizeof(vlnk));
5827 grub_file_read(file, &vlnk, sizeof(vlnk));
5828
5829 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5830
5831 out:
5832
5833 grub_refresh();
5834 check_free(file, grub_file_close);
5835 grub_errno = GRUB_ERR_NONE;
5836 return ret;
5837 }
5838
5839 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5840 {
5841 (void)ctxt;
5842 (void)argc;
5843 (void)args;
5844
5845 g_iso_vd_id_publisher[0] = 0;
5846 g_iso_vd_id_prepare[0] = 0;
5847 g_iso_vd_id_application[0] = 0;
5848
5849 return 0;
5850 }
5851
5852 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
5853 {
5854 int ret = 1;
5855 int offset = 318;
5856 grub_file_t file = NULL;
5857
5858 (void)ctxt;
5859 (void)argc;
5860
5861 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5862 if (!file)
5863 {
5864 grub_printf("Failed to open %s\n", args[0]);
5865 goto out;
5866 }
5867
5868 grub_file_seek(file, 16 * 2048 + offset);
5869 grub_file_read(file, g_iso_vd_id_publisher, 128);
5870
5871 offset += 128;
5872 grub_file_seek(file, 16 * 2048 + offset);
5873 grub_file_read(file, g_iso_vd_id_prepare, 128);
5874
5875 offset += 128;
5876 grub_file_seek(file, 16 * 2048 + offset);
5877 grub_file_read(file, g_iso_vd_id_application, 128);
5878
5879 out:
5880
5881 check_free(file, grub_file_close);
5882 grub_errno = GRUB_ERR_NONE;
5883 return ret;
5884 }
5885
5886 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
5887 {
5888 int ret = 1;
5889 char *id = g_iso_vd_id_publisher;
5890
5891 (void)ctxt;
5892 (void)argc;
5893
5894 if (args[0][0] == '1')
5895 {
5896 id = g_iso_vd_id_prepare;
5897 }
5898 else if (args[0][0] == '2')
5899 {
5900 id = g_iso_vd_id_application;
5901 }
5902
5903 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
5904 {
5905 ret = 0;
5906 }
5907
5908 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
5909 {
5910 ret = 0;
5911 }
5912
5913 grub_errno = GRUB_ERR_NONE;
5914 return ret;
5915 }
5916
5917 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
5918 {
5919 (void)ctxt;
5920 (void)argc;
5921
5922 g_ventoy_fn_mutex = 0;
5923 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
5924 {
5925 g_ventoy_fn_mutex = 1;
5926 }
5927
5928 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5929 }
5930
5931 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
5932 {
5933 grub_uint64_t total;
5934 grub_uint64_t org_required;
5935 grub_uint64_t new_required;
5936
5937 (void)ctxt;
5938 (void)argc;
5939 (void)args;
5940
5941 #ifdef GRUB_MACHINE_EFI
5942 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
5943 grub_printf("Total pages: %llu\n", (unsigned long long)total);
5944 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
5945 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
5946 #else
5947 (void)total;
5948 (void)org_required;
5949 (void)new_required;
5950 grub_printf("Non EFI mode!\n");
5951 #endif
5952
5953 grub_refresh();
5954
5955 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5956 }
5957
5958 int ventoy_env_init(void)
5959 {
5960 int i;
5961 char buf[64];
5962
5963 grub_env_set("vtdebug_flag", "");
5964
5965 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
5966 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5967 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5968 for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++)
5969 {
5970 g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size);
5971 }
5972
5973 ventoy_filt_register(0, ventoy_wrapper_open);
5974
5975 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
5976 if (g_grub_param)
5977 {
5978 g_grub_param->grub_env_get = grub_env_get;
5979 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5980 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5981 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5982 grub_env_set("env_param", buf);
5983 grub_env_set("ventoy_env_param", buf);
5984
5985 grub_env_export("env_param");
5986 grub_env_export("ventoy_env_param");
5987 }
5988
5989 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5990 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5991
5992 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5993 grub_env_set("vtoy_winpeshl_ini_size", buf);
5994
5995 grub_env_export("vtoy_winpeshl_ini_addr");
5996 grub_env_export("vtoy_winpeshl_ini_size");
5997
5998 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
5999 grub_env_set("vtoy_chain_file_size", buf);
6000 grub_env_export("vtoy_chain_file_size");
6001
6002 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
6003 grub_env_set("vtoy_chain_file_read", buf);
6004 grub_env_export("vtoy_chain_file_read");
6005
6006 return 0;
6007 }
6008
6009
6010
6011 static cmd_para ventoy_cmds[] =
6012 {
6013 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
6014 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
6015 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
6016 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
6017 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
6018 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
6019 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
6020 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6021 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6022 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
6023 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
6024 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
6025 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
6026 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
6027 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
6028 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
6029 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
6030 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
6031 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
6032 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
6033 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
6034 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
6035 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
6036 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
6037 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
6038 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
6039 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
6040
6041 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
6042 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
6043 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
6044 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
6045 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
6046 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
6047 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
6048
6049 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
6050 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
6051 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
6052 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
6053 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
6054 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
6055 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
6056 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
6057 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
6058 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
6059
6060
6061 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
6062 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
6063 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
6064 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
6065 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
6066 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
6067 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
6068 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
6069 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
6070 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
6071 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
6072
6073 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
6074 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
6075 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
6076 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
6077 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
6078 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
6079 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
6080
6081 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6082 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6083 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
6084 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
6085 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
6086 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
6087 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
6088 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
6089 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
6090 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
6091
6092 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
6093 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
6094 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
6095 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
6096 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
6097 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
6098 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
6099 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
6100 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
6101
6102 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
6103 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
6104 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
6105 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
6106
6107
6108 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
6109 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
6110 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
6111
6112 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
6113 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
6114 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
6115
6116
6117 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
6118 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
6119 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
6120 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
6121 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
6122 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
6123 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
6124 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
6125 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
6126 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
6127 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
6128 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
6129 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
6130 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
6131
6132 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
6133 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
6134 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
6135 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
6136 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
6137 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
6138 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
6139 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
6140 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
6141 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
6142 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
6143 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
6144
6145 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
6146 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
6147 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
6148 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
6149 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
6150 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
6151 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
6152 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
6153 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
6154 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
6155 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
6156 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
6157 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
6158 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
6159 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
6160 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
6161 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
6162 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
6163 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
6164 };
6165
6166 int ventoy_register_all_cmd(void)
6167 {
6168 grub_uint32_t i;
6169 cmd_para *cur = NULL;
6170
6171 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6172 {
6173 cur = ventoy_cmds + i;
6174 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
6175 cur->summary, cur->description, cur->parser);
6176 }
6177
6178 return 0;
6179 }
6180
6181 int ventoy_unregister_all_cmd(void)
6182 {
6183 grub_uint32_t i;
6184
6185 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6186 {
6187 grub_unregister_extcmd(ventoy_cmds[i].cmd);
6188 }
6189
6190 return 0;
6191 }
6192
6193