]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
562ede6c9e76d8d1182717da0d74994ebf5faa05
[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 goto load;
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 load:
3686 grub_check_free(node->filebuf);
3687 node->filelen = 0;
3688
3689 if (node->cursel >= 0 && node->cursel < node->templatenum)
3690 {
3691 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"),
3692 node->templatepath[node->cursel].path);
3693 if (file)
3694 {
3695 node->filebuf = grub_malloc(file->size + 8);
3696 if (node->filebuf)
3697 {
3698 grub_file_read(file, node->filebuf, file->size);
3699 grub_file_close(file);
3700
3701 grub_memset(node->filebuf + file->size, 0, 8);
3702 node->filelen = (int)file->size;
3703
3704 ventoy_auto_install_var_expand(node);
3705 }
3706 }
3707 else
3708 {
3709 debug("Failed to open auto install script <%s%s>\n",
3710 ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path);
3711 }
3712 }
3713
3714 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3715 }
3716
3717 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3718 {
3719 int i = 0;
3720 int pos = 0;
3721 int defidx = 1;
3722 char *buf = NULL;
3723 char configfile[128];
3724 persistence_config *node;
3725
3726 (void)ctxt;
3727 (void)argc;
3728 (void)args;
3729
3730 debug("select persistence argc:%d\n", argc);
3731
3732 if (argc < 1)
3733 {
3734 return 0;
3735 }
3736
3737 node = ventoy_plugin_find_persistent(args[0]);
3738 if (!node)
3739 {
3740 debug("Persistence image not found for %s\n", args[0]);
3741 return 0;
3742 }
3743
3744 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3745 {
3746 defidx = node->autosel;
3747 if (node->timeout < 0)
3748 {
3749 node->cursel = node->autosel - 1;
3750 debug("Persistence image auto select %d\n", node->autosel);
3751 return 0;
3752 }
3753 }
3754
3755 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3756 if (!buf)
3757 {
3758 return 0;
3759 }
3760
3761 if (node->timeout > 0)
3762 {
3763 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3764 }
3765
3766 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3767 " echo %s\n}\n", "");
3768
3769 for (i = 0; i < node->backendnum; i++)
3770 {
3771 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3772 " echo \"\"\n}\n",
3773 node->backendpath[i].path);
3774
3775 }
3776
3777 g_ventoy_menu_esc = 1;
3778 g_ventoy_suppress_esc = 1;
3779 g_ventoy_suppress_esc_default = defidx;
3780
3781 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3782 grub_script_execute_sourcecode(configfile);
3783
3784 g_ventoy_menu_esc = 0;
3785 g_ventoy_suppress_esc = 0;
3786 g_ventoy_suppress_esc_default = 1;
3787
3788 grub_free(buf);
3789
3790 node->cursel = g_ventoy_last_entry - 1;
3791
3792 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3793 }
3794
3795 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3796 {
3797 grub_uint32_t i;
3798 ventoy_img_chunk *cur;
3799
3800 (void)ctxt;
3801 (void)argc;
3802 (void)args;
3803
3804 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3805 {
3806 cur = g_img_chunk_list.chunk + i;
3807 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3808 cur->img_start_sector, cur->img_end_sector,
3809 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3810 );
3811 }
3812
3813 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3814 }
3815
3816 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3817 {
3818 grub_uint32_t i;
3819 grub_file_t file;
3820 ventoy_img_chunk_list chunklist;
3821
3822 (void)ctxt;
3823 (void)argc;
3824
3825 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3826 if (!file)
3827 {
3828 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3829 }
3830
3831 /* get image chunk data */
3832 grub_memset(&chunklist, 0, sizeof(chunklist));
3833 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3834 if (NULL == chunklist.chunk)
3835 {
3836 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3837 }
3838
3839 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3840 chunklist.cur_chunk = 0;
3841
3842 ventoy_get_block_list(file, &chunklist, 0);
3843
3844 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3845 {
3846 grub_printf("########## UNSUPPORTED ###############\n");
3847 }
3848
3849 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3850
3851 for (i = 0; i < chunklist.cur_chunk; i++)
3852 {
3853 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3854 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3855 }
3856
3857 grub_printf("\n==================================\n");
3858
3859 for (i = 0; i < chunklist.cur_chunk; i++)
3860 {
3861 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3862 (ulonglong)chunklist.chunk[i].img_start_sector,
3863 (ulonglong)chunklist.chunk[i].img_end_sector,
3864 (ulonglong)chunklist.chunk[i].disk_start_sector,
3865 (ulonglong)chunklist.chunk[i].disk_end_sector
3866 );
3867 }
3868
3869 grub_free(chunklist.chunk);
3870 grub_file_close(file);
3871
3872 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3873 }
3874
3875 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3876 {
3877 int i;
3878 ventoy_grub_param_file_replace *replace = NULL;
3879
3880 (void)ctxt;
3881 (void)argc;
3882 (void)args;
3883
3884 if (argc >= 2)
3885 {
3886 replace = &(g_grub_param->file_replace);
3887 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3888
3889 replace->old_name_cnt = 0;
3890 for (i = 0; i < 4 && i + 1 < argc; i++)
3891 {
3892 replace->old_name_cnt++;
3893 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3894 }
3895
3896 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3897 }
3898
3899 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3900 }
3901
3902 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3903 {
3904 char buf[32];
3905 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3906
3907 (void)ctxt;
3908
3909 if (argc >= 1)
3910 {
3911 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3912 grub_env_set(args[0], buf);
3913 }
3914
3915 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3916 }
3917
3918 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3919 {
3920 (void)ctxt;
3921 (void)argc;
3922 (void)args;
3923
3924 if (argc == 0)
3925 {
3926 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3927 grub_printf("%s", g_list_script_buf);
3928 }
3929 else
3930 {
3931 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3932 grub_printf("%s", g_tree_script_buf);
3933 }
3934
3935 return 0;
3936 }
3937
3938 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3939 {
3940 img_info *cur = g_ventoy_img_list;
3941
3942 (void)ctxt;
3943 (void)argc;
3944 (void)args;
3945
3946 while (cur)
3947 {
3948 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3949 grub_printf("name:<%s>\n\n", cur->name);
3950 cur = cur->next;
3951 }
3952
3953 return 0;
3954 }
3955
3956 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3957 {
3958 (void)ctxt;
3959 (void)argc;
3960 (void)args;
3961
3962 ventoy_plugin_dump_injection();
3963
3964 return 0;
3965 }
3966
3967 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3968 {
3969 (void)ctxt;
3970 (void)argc;
3971 (void)args;
3972
3973 ventoy_plugin_dump_auto_install();
3974
3975 return 0;
3976 }
3977
3978 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3979 {
3980 (void)ctxt;
3981 (void)argc;
3982 (void)args;
3983
3984 ventoy_plugin_dump_persistence();
3985
3986 return 0;
3987 }
3988
3989 static int ventoy_check_mode_by_name(char *filename, const char *suffix)
3990 {
3991 int i;
3992 int len1;
3993 int len2;
3994
3995 len1 = (int)grub_strlen(filename);
3996 len2 = (int)grub_strlen(suffix);
3997
3998 if (len1 <= len2)
3999 {
4000 return 0;
4001 }
4002
4003 for (i = len1 - 1; i >= 0; i--)
4004 {
4005 if (filename[i] == '.')
4006 {
4007 break;
4008 }
4009 }
4010
4011 if (i < len2 + 1)
4012 {
4013 return 0;
4014 }
4015
4016 if (filename[i - len2 - 1] != '_')
4017 {
4018 return 0;
4019 }
4020
4021 if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0)
4022 {
4023 return 1;
4024 }
4025
4026 return 0;
4027 }
4028
4029 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4030 {
4031 (void)ctxt;
4032 (void)argc;
4033 (void)args;
4034
4035 if (argc != 1 && argc != 2)
4036 {
4037 return 1;
4038 }
4039
4040 if (args[0][0] == '0')
4041 {
4042 if (g_ventoy_memdisk_mode)
4043 {
4044 return 0;
4045 }
4046
4047 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk"))
4048 {
4049 return 0;
4050 }
4051
4052 return 1;
4053 }
4054 else if (args[0][0] == '1')
4055 {
4056 return g_ventoy_iso_raw ? 0 : 1;
4057 }
4058 else if (args[0][0] == '2')
4059 {
4060 return g_ventoy_iso_uefi_drv ? 0 : 1;
4061 }
4062 else if (args[0][0] == '3')
4063 {
4064 if (g_ventoy_grub2_mode)
4065 {
4066 return 0;
4067 }
4068
4069 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2"))
4070 {
4071 return 0;
4072 }
4073
4074 return 1;
4075 }
4076 else if (args[0][0] == '4')
4077 {
4078 if (g_ventoy_wimboot_mode)
4079 {
4080 return 0;
4081 }
4082
4083 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot"))
4084 {
4085 return 0;
4086 }
4087
4088 return 1;
4089 }
4090
4091 return 1;
4092 }
4093
4094 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
4095 {
4096 static int configfile_mode = 0;
4097 char memfile[128] = {0};
4098
4099 (void)ctxt;
4100 (void)argc;
4101 (void)args;
4102
4103 /*
4104 * args[0]: 0:normal 1:configfile
4105 * args[1]: 0:list_buf 1:tree_buf
4106 */
4107
4108 if (argc != 2)
4109 {
4110 debug("Invalid argc %d\n", argc);
4111 return 0;
4112 }
4113
4114 VTOY_CMD_CHECK(1);
4115
4116 if (args[0][0] == '0')
4117 {
4118 if (args[1][0] == '0')
4119 {
4120 grub_script_execute_sourcecode(g_list_script_buf);
4121 }
4122 else
4123 {
4124 grub_script_execute_sourcecode(g_tree_script_buf);
4125 }
4126 }
4127 else
4128 {
4129 if (configfile_mode)
4130 {
4131 debug("Now already in F3 mode %d\n", configfile_mode);
4132 return 0;
4133 }
4134
4135 if (args[1][0] == '0')
4136 {
4137 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4138 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
4139 }
4140 else
4141 {
4142 g_ventoy_last_entry = -1;
4143 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4144 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
4145 }
4146
4147 configfile_mode = 1;
4148 grub_script_execute_sourcecode(memfile);
4149 configfile_mode = 0;
4150 }
4151
4152 return 0;
4153 }
4154
4155 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
4156 {
4157 grub_file_t file;
4158
4159 (void)ctxt;
4160
4161 if (argc != 1)
4162 {
4163 return 1;
4164 }
4165
4166 g_ventoy_case_insensitive = 1;
4167 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4168 g_ventoy_case_insensitive = 0;
4169
4170 grub_errno = 0;
4171
4172 if (file)
4173 {
4174 grub_file_close(file);
4175 return 0;
4176 }
4177 return 1;
4178 }
4179
4180 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
4181 {
4182 int id = 0;
4183 int find = 0;
4184 grub_disk_t disk;
4185 const char *isopath = NULL;
4186 char hdname[32];
4187 ventoy_mbr_head mbr;
4188
4189 (void)ctxt;
4190 (void)argc;
4191
4192 if (argc != 1)
4193 {
4194 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
4195 }
4196
4197 isopath = grub_env_get("vtoy_iso_part");
4198 if (!isopath)
4199 {
4200 debug("isopath is null %p\n", isopath);
4201 return 0;
4202 }
4203
4204 debug("isopath is %s\n", isopath);
4205
4206 for (id = 0; id < 30 && (find == 0); id++)
4207 {
4208 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
4209 if (grub_strstr(isopath, hdname))
4210 {
4211 debug("skip %s ...\n", hdname);
4212 continue;
4213 }
4214
4215 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
4216
4217 disk = grub_disk_open(hdname);
4218 if (!disk)
4219 {
4220 debug("%s not exist\n", hdname);
4221 break;
4222 }
4223
4224 grub_memset(&mbr, 0, sizeof(mbr));
4225 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
4226 {
4227 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
4228 {
4229 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
4230 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
4231 {
4232
4233 grub_env_set(args[0], hdname);
4234 find = 1;
4235 }
4236 }
4237 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
4238 }
4239 else
4240 {
4241 debug("read %s failed\n", hdname);
4242 }
4243
4244 grub_disk_close(disk);
4245 }
4246
4247 return 0;
4248 }
4249
4250 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
4251 {
4252 int len = 1024;
4253 grub_file_t file;
4254 char *buf = NULL;
4255
4256 (void)ctxt;
4257 (void)argc;
4258
4259 if (argc != 2)
4260 {
4261 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
4262 }
4263
4264 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4265 if (!file)
4266 {
4267 debug("failed to open file %s\n", args[0]);
4268 return 0;
4269 }
4270
4271 buf = grub_malloc(len);
4272 if (!buf)
4273 {
4274 goto end;
4275 }
4276
4277 buf[len - 1] = 0;
4278 grub_file_read(file, buf, len - 1);
4279
4280 ventoy_get_line(buf);
4281 ventoy_set_env(args[1], buf);
4282
4283 end:
4284
4285 grub_check_free(buf);
4286 grub_file_close(file);
4287
4288 return 0;
4289 }
4290
4291 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
4292 {
4293 grub_uint64_t end_max = 0;
4294 int *pCnt = (int *)data;
4295
4296 (void)disk;
4297
4298 (*pCnt)++;
4299 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
4300 "0 %llu linear /dev/ventoy %llu\n",
4301 (ulonglong)partition->len, (ulonglong)partition->start);
4302
4303 end_max = (partition->len + partition->start) * 512;
4304 if (end_max > g_part_end_max)
4305 {
4306 g_part_end_max = end_max;
4307 }
4308
4309 return 0;
4310 }
4311
4312 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
4313 {
4314 int cnt = 0;
4315 char *device_name = NULL;
4316 grub_device_t dev = NULL;
4317 char buf[64];
4318
4319 (void)ctxt;
4320
4321 g_part_list_pos = 0;
4322 g_part_end_max = 0;
4323 grub_env_unset("vtoy_img_part_file");
4324
4325 if (argc != 1)
4326 {
4327 return 1;
4328 }
4329
4330 device_name = grub_file_get_device_name(args[0]);
4331 if (!device_name)
4332 {
4333 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
4334 goto end;
4335 }
4336
4337 dev = grub_device_open(device_name);
4338 if (!dev)
4339 {
4340 debug("grub_device_open failed, %s\n", device_name);
4341 goto end;
4342 }
4343
4344 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
4345
4346 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
4347 grub_env_set("vtoy_img_part_file", buf);
4348
4349 grub_snprintf(buf, sizeof(buf), "%d", cnt);
4350 grub_env_set("vtoy_img_part_cnt", buf);
4351
4352 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max);
4353 grub_env_set("vtoy_img_max_part_end", buf);
4354
4355 end:
4356
4357 check_free(device_name, grub_free);
4358 check_free(dev, grub_device_close);
4359
4360 return 0;
4361 }
4362
4363
4364 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
4365 {
4366 int rc = 1;
4367 grub_file_t file;
4368 char *buf = NULL;
4369
4370 (void)ctxt;
4371 (void)argc;
4372
4373 if (argc != 2)
4374 {
4375 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
4376 }
4377
4378 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4379 if (!file)
4380 {
4381 debug("failed to open file %s\n", args[0]);
4382 return 1;
4383 }
4384
4385 buf = grub_malloc(file->size + 1);
4386 if (!buf)
4387 {
4388 goto end;
4389 }
4390
4391 buf[file->size] = 0;
4392 grub_file_read(file, buf, file->size);
4393
4394 if (grub_strstr(buf, args[1]))
4395 {
4396 rc = 0;
4397 }
4398
4399 end:
4400
4401 grub_check_free(buf);
4402 grub_file_close(file);
4403
4404 return rc;
4405 }
4406
4407 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
4408 {
4409 int len;
4410 grub_file_t file;
4411 char buf[64];
4412 grub_uint64_t size;
4413 ventoy_iso9660_vd pvd;
4414
4415 (void)ctxt;
4416 (void)argc;
4417
4418 if (argc != 4)
4419 {
4420 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
4421 }
4422
4423 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4424 if (!file)
4425 {
4426 debug("failed to open file %s\n", args[0]);
4427 return 0;
4428 }
4429
4430 grub_file_seek(file, 16 * 2048);
4431 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
4432 if (len != sizeof(pvd))
4433 {
4434 debug("failed to read pvd %d\n", len);
4435 goto end;
4436 }
4437
4438 grub_memset(buf, 0, sizeof(buf));
4439 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
4440 ventoy_set_env(args[1], buf);
4441
4442 grub_memset(buf, 0, sizeof(buf));
4443 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
4444 ventoy_set_env(args[2], buf);
4445
4446 size = pvd.space;
4447 size *= 2048;
4448 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
4449 ventoy_set_env(args[3], buf);
4450
4451 end:
4452 grub_file_close(file);
4453
4454 return 0;
4455 }
4456
4457 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
4458 {
4459 int len;
4460 grub_file_t file;
4461 char buf[64];
4462
4463 (void)ctxt;
4464 (void)argc;
4465
4466 if (argc != 2)
4467 {
4468 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
4469 }
4470
4471 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4472 if (!file)
4473 {
4474 debug("failed to open file %s\n", args[0]);
4475 return 0;
4476 }
4477
4478 grub_memset(buf, 0, sizeof(buf));
4479 grub_file_seek(file, 16 * 2048 + 813);
4480 len = (int)grub_file_read(file, buf, 17);
4481 if (len != 17)
4482 {
4483 debug("failed to read create date %d\n", len);
4484 goto end;
4485 }
4486
4487 ventoy_set_env(args[1], buf);
4488
4489 end:
4490 grub_file_close(file);
4491
4492 return 0;
4493 }
4494
4495 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4496 {
4497 (void)ctxt;
4498 (void)argc;
4499 (void)args;
4500
4501 ventoy_env_hook_root(1);
4502
4503 return 0;
4504 }
4505
4506 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4507 {
4508 (void)ctxt;
4509 (void)argc;
4510 (void)args;
4511
4512 ventoy_env_hook_root(0);
4513
4514 return 0;
4515 }
4516
4517 #ifdef GRUB_MACHINE_EFI
4518 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4519 {
4520 int ret = 1;
4521 grub_uint8_t *var;
4522 grub_size_t size;
4523 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4524
4525 (void)ctxt;
4526 (void)argc;
4527 (void)args;
4528
4529 var = grub_efi_get_variable("SecureBoot", &global, &size);
4530 if (var && *var == 1)
4531 {
4532 return 0;
4533 }
4534
4535 return ret;
4536 }
4537 #else
4538 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4539 {
4540 (void)ctxt;
4541 (void)argc;
4542 (void)args;
4543 return 1;
4544 }
4545 #endif
4546
4547 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
4548 {
4549 int i;
4550 int ret = 1;
4551 grub_file_t file;
4552 grub_uint64_t FileSectors = 0;
4553 ventoy_gpt_info *gpt = NULL;
4554 ventoy_part_table *pt = NULL;
4555 grub_uint8_t zeroguid[16] = {0};
4556
4557 (void)ctxt;
4558 (void)argc;
4559
4560 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4561 if (!file)
4562 {
4563 debug("failed to open file %s\n", args[0]);
4564 return 1;
4565 }
4566
4567 if (file->size % 512)
4568 {
4569 debug("unaligned file size: %llu\n", (ulonglong)file->size);
4570 goto out;
4571 }
4572
4573 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
4574 if (!gpt)
4575 {
4576 goto out;
4577 }
4578
4579 FileSectors = file->size / 512;
4580
4581 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
4582 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
4583 {
4584 debug("This is EFI partition table\n");
4585
4586 for (i = 0; i < 128; i++)
4587 {
4588 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
4589 {
4590 if (FileSectors < gpt->PartTbl[i].LastLBA)
4591 {
4592 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4593 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
4594 goto out;
4595 }
4596 }
4597 }
4598 }
4599 else
4600 {
4601 debug("This is MBR partition table\n");
4602
4603 for (i = 0; i < 4; i++)
4604 {
4605 pt = gpt->MBR.PartTbl + i;
4606 if (FileSectors < pt->StartSectorId + pt->SectorCount)
4607 {
4608 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4609 (ulonglong)(pt->StartSectorId + pt->SectorCount),
4610 (ulonglong)FileSectors);
4611 goto out;
4612 }
4613 }
4614 }
4615
4616 ret = 0;
4617
4618 out:
4619 grub_file_close(file);
4620 grub_check_free(gpt);
4621 grub_errno = GRUB_ERR_NONE;
4622 return ret;
4623 }
4624
4625 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
4626 {
4627 int i;
4628 int ret;
4629
4630 (void)ctxt;
4631 (void)argc;
4632 (void)args;
4633
4634 for (i = 0; i < 500; i++)
4635 {
4636 ret = grub_getkey_noblock();
4637 if (ret == GRUB_TERM_NO_KEY)
4638 {
4639 break;
4640 }
4641 }
4642
4643 if (i >= 500)
4644 {
4645 grub_cls();
4646 grub_printf("\n\n Still have key input after clear.\n");
4647 grub_refresh();
4648 grub_sleep(5);
4649 }
4650
4651 return 0;
4652 }
4653
4654 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4655 {
4656 int i;
4657 int buflen;
4658 int datalen;
4659 int loclen;
4660 int img_chunk_num;
4661 int image_sector_size;
4662 char cmd[64];
4663 ventoy_chain_head *chain;
4664 ventoy_img_chunk *chunk;
4665 ventoy_os_param *osparam;
4666 ventoy_image_location *location;
4667 ventoy_image_disk_region *region;
4668 struct grub_acpi_table_header *acpi;
4669
4670 (void)ctxt;
4671
4672 if (argc != 2)
4673 {
4674 return 1;
4675 }
4676
4677 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4678
4679 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4680 if (!chain)
4681 {
4682 return 1;
4683 }
4684
4685 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4686
4687 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4688 {
4689 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4690 return 1;
4691 }
4692
4693 img_chunk_num = chain->img_chunk_num;
4694
4695 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4696 datalen = sizeof(ventoy_os_param) + loclen;
4697
4698 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4699 acpi = grub_zalloc(buflen);
4700 if (!acpi)
4701 {
4702 return 1;
4703 }
4704
4705 /* Step1: Fill acpi table header */
4706 grub_memcpy(acpi->signature, "VTOY", 4);
4707 acpi->length = buflen;
4708 acpi->revision = 1;
4709 grub_memcpy(acpi->oemid, "VENTOY", 6);
4710 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4711 acpi->oemrev = 1;
4712 acpi->creator_id[0] = 1;
4713 acpi->creator_rev = 1;
4714
4715 /* Step2: Fill data */
4716 osparam = (ventoy_os_param *)(acpi + 1);
4717 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4718 osparam->vtoy_img_location_addr = 0;
4719 osparam->vtoy_img_location_len = loclen;
4720 osparam->chksum = 0;
4721 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4722
4723 location = (ventoy_image_location *)(osparam + 1);
4724 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4725 location->image_sector_size = image_sector_size;
4726 location->disk_sector_size = chain->disk_sector_size;
4727 location->region_count = img_chunk_num;
4728
4729 region = location->regions;
4730 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4731 if (512 == image_sector_size)
4732 {
4733 for (i = 0; i < img_chunk_num; i++)
4734 {
4735 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4736 region->image_start_sector = chunk->img_start_sector * 4;
4737 region->disk_start_sector = chunk->disk_start_sector;
4738 region++;
4739 chunk++;
4740 }
4741 }
4742 else
4743 {
4744 for (i = 0; i < img_chunk_num; i++)
4745 {
4746 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4747 region->image_start_sector = chunk->img_start_sector;
4748 region->disk_start_sector = chunk->disk_start_sector;
4749 region++;
4750 chunk++;
4751 }
4752 }
4753
4754 /* Step3: Fill acpi checksum */
4755 acpi->checksum = 0;
4756 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4757
4758 /* load acpi table */
4759 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4760 grub_script_execute_sourcecode(cmd);
4761
4762 grub_free(acpi);
4763
4764 VENTOY_CMD_RETURN(0);
4765 }
4766
4767 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4768 {
4769 (void)ctxt;
4770 (void)argc;
4771 (void)args;
4772
4773 g_ventoy_last_entry_back = g_ventoy_last_entry;
4774 g_ventoy_last_entry = -1;
4775
4776 return 0;
4777 }
4778
4779 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4780 {
4781 (void)ctxt;
4782 (void)argc;
4783 (void)args;
4784
4785 g_ventoy_last_entry = g_ventoy_last_entry_back;
4786
4787 return 0;
4788 }
4789
4790 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4791 {
4792 const char *pos = filename + 1;
4793
4794 if (info->dir)
4795 {
4796 while (*pos)
4797 {
4798 if (*pos == '.')
4799 {
4800 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4801 {
4802 grub_strncpy((char *)data, filename, 128);
4803 return 1;
4804 }
4805 }
4806 pos++;
4807 }
4808 }
4809
4810 return 0;
4811 }
4812
4813 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4814 {
4815 int rc = 1;
4816 char *device_name = NULL;
4817 grub_device_t dev = NULL;
4818 grub_fs_t fs = NULL;
4819 char buf[128] = {0};
4820
4821 (void)ctxt;
4822
4823 if (argc != 3)
4824 {
4825 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4826 return 1;
4827 }
4828
4829 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4830
4831 device_name = grub_file_get_device_name(args[0]);
4832 if (!device_name)
4833 {
4834 debug("grub_file_get_device_name failed, %s\n", args[0]);
4835 goto end;
4836 }
4837
4838 dev = grub_device_open(device_name);
4839 if (!dev)
4840 {
4841 debug("grub_device_open failed, %s\n", device_name);
4842 goto end;
4843 }
4844
4845 fs = grub_fs_probe(dev);
4846 if (!fs)
4847 {
4848 debug("grub_fs_probe failed, %s\n", device_name);
4849 goto end;
4850 }
4851
4852 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4853
4854 if (buf[0])
4855 {
4856 ventoy_set_env(args[2], buf);
4857 }
4858
4859 rc = 0;
4860
4861 end:
4862
4863 check_free(device_name, grub_free);
4864 check_free(dev, grub_device_close);
4865
4866 return rc;
4867 }
4868
4869 int ventoy_load_part_table(const char *diskname)
4870 {
4871 char name[64];
4872 int ret;
4873 grub_disk_t disk;
4874 grub_device_t dev;
4875
4876 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4877 if (!g_ventoy_part_info)
4878 {
4879 return 1;
4880 }
4881
4882 disk = grub_disk_open(diskname);
4883 if (!disk)
4884 {
4885 debug("Failed to open disk %s\n", diskname);
4886 return 1;
4887 }
4888
4889 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4890
4891 g_ventoy_disk_bios_id = disk->id;
4892
4893 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4894 grub_disk_close(disk);
4895
4896 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4897 dev = grub_device_open(name);
4898 if (dev)
4899 {
4900 /* Check for official Ventoy device */
4901 ret = ventoy_check_official_device(dev);
4902 grub_device_close(dev);
4903
4904 if (ret)
4905 {
4906 return 1;
4907 }
4908 }
4909
4910 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4911 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4912
4913 return 0;
4914 }
4915
4916 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4917 {
4918 int ret;
4919
4920 (void)argc;
4921 (void)ctxt;
4922
4923 ret = ventoy_load_part_table(args[0]);
4924 if (ret)
4925 {
4926 grub_exit();
4927 }
4928
4929 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4930 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4931
4932 return 0;
4933 }
4934
4935 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4936 {
4937 int ret = 1;
4938 const char *vcfg = NULL;
4939
4940 (void)argc;
4941 (void)ctxt;
4942
4943 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4944 if (vcfg)
4945 {
4946 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4947 grub_env_set(args[1], vcfg);
4948 ret = 0;
4949 }
4950 else
4951 {
4952 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4953 }
4954
4955 grub_errno = 0;
4956 return ret;
4957 }
4958
4959
4960 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4961 {
4962 int id;
4963 grub_uint8_t zeroguid[16] = {0};
4964
4965 (void)argc;
4966 (void)ctxt;
4967
4968 id = (int)grub_strtoul(args[0], NULL, 10);
4969 grub_errno = 0;
4970
4971 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4972 {
4973 if (id >= 1 && id <= 128)
4974 {
4975 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4976 {
4977 return 0;
4978 }
4979 }
4980 }
4981 else
4982 {
4983 if (id >= 1 && id <= 4)
4984 {
4985 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4986 {
4987 return 0;
4988 }
4989 }
4990 }
4991
4992 return 1;
4993 }
4994
4995 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4996 {
4997 int rc = 1;
4998 char *device_name = NULL;
4999 grub_device_t dev = NULL;
5000 grub_fs_t fs = NULL;
5001 char *label = NULL;
5002
5003 (void)ctxt;
5004
5005 debug("get fs label for %s\n", args[0]);
5006
5007 if (argc != 2)
5008 {
5009 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
5010 return 1;
5011 }
5012
5013 device_name = grub_file_get_device_name(args[0]);
5014 if (!device_name)
5015 {
5016 debug("grub_file_get_device_name failed, %s\n", args[0]);
5017 goto end;
5018 }
5019
5020 dev = grub_device_open(device_name);
5021 if (!dev)
5022 {
5023 debug("grub_device_open failed, %s\n", device_name);
5024 goto end;
5025 }
5026
5027 fs = grub_fs_probe(dev);
5028 if (NULL == fs || NULL == fs->fs_label)
5029 {
5030 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
5031 goto end;
5032 }
5033
5034 fs->fs_label(dev, &label);
5035 if (label)
5036 {
5037 debug("label=<%s>\n", label);
5038 ventoy_set_env(args[1], label);
5039 grub_free(label);
5040 }
5041
5042 rc = 0;
5043
5044 end:
5045
5046 check_free(device_name, grub_free);
5047 check_free(dev, grub_device_close);
5048
5049 return rc;
5050 }
5051
5052 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5053 {
5054 if (!info->dir)
5055 {
5056 grub_snprintf((char *)data, 256, "%s", filename);
5057 return 1;
5058 }
5059
5060 return 0;
5061 }
5062
5063 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5064 {
5065 if (info->dir && filename && filename[0] != '.')
5066 {
5067 grub_snprintf((char *)data, 256, "%s", filename);
5068 return 1;
5069 }
5070
5071 return 0;
5072 }
5073
5074 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
5075 {
5076 int rc = 1;
5077 char *device_name = NULL;
5078 grub_device_t dev = NULL;
5079 grub_fs_t fs = NULL;
5080 char name[256] ={0};
5081
5082 if (argc != 3)
5083 {
5084 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
5085 return 1;
5086 }
5087
5088 device_name = grub_file_get_device_name(args[0]);
5089 if (!device_name)
5090 {
5091 debug("grub_file_get_device_name failed, %s\n", args[0]);
5092 goto end;
5093 }
5094
5095 dev = grub_device_open(device_name);
5096 if (!dev)
5097 {
5098 debug("grub_device_open failed, %s\n", device_name);
5099 goto end;
5100 }
5101
5102 fs = grub_fs_probe(dev);
5103 if (!fs)
5104 {
5105 debug("grub_fs_probe failed, %s\n", device_name);
5106 goto end;
5107 }
5108
5109 fs->fs_dir(dev, args[1], hook, name);
5110 if (name[0])
5111 {
5112 ventoy_set_env(args[2], name);
5113 }
5114
5115 rc = 0;
5116
5117 end:
5118
5119 check_free(device_name, grub_free);
5120 check_free(dev, grub_device_close);
5121
5122 return rc;
5123 }
5124
5125 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
5126 {
5127 (void)ctxt;
5128 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
5129 }
5130
5131 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
5132 {
5133 (void)ctxt;
5134 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
5135 }
5136
5137 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
5138 {
5139 char c;
5140 char *pos = NULL;
5141 char *end = NULL;
5142
5143 (void)ctxt;
5144
5145 if (argc != 2)
5146 {
5147 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
5148 return 1;
5149 }
5150
5151 for (pos = args[0]; *pos; pos++)
5152 {
5153 if (*pos == '.')
5154 {
5155 end = pos;
5156 }
5157 }
5158
5159 if (end)
5160 {
5161 c = *end;
5162 *end = 0;
5163 }
5164
5165 grub_env_set(args[1], args[0]);
5166
5167 if (end)
5168 {
5169 *end = c;
5170 }
5171
5172 return 0;
5173 }
5174
5175 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
5176 {
5177 int i;
5178 int len;
5179 const char *buf;
5180
5181 (void)ctxt;
5182
5183 if (argc != 2)
5184 {
5185 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
5186 return 1;
5187 }
5188
5189 buf = args[0];
5190 len = (int)grub_strlen(buf);
5191 for (i = len; i > 0; i--)
5192 {
5193 if (buf[i - 1] == '/')
5194 {
5195 grub_env_set(args[1], buf + i);
5196 return 0;
5197 }
5198 }
5199
5200 grub_env_set(args[1], buf);
5201
5202 return 0;
5203 }
5204
5205 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5206 {
5207 struct grub_video_mode_info info;
5208 char buf[32];
5209
5210 (void)ctxt;
5211 (void)argc;
5212 (void)args;
5213
5214 if (!g_video_mode_list)
5215 {
5216 ventoy_enum_video_mode();
5217 }
5218
5219 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5220 {
5221 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
5222 }
5223 else
5224 {
5225 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
5226 }
5227
5228 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
5229
5230 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
5231 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
5232
5233 VENTOY_CMD_RETURN(0);
5234 }
5235
5236 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5237 {
5238 struct grub_video_mode_info info;
5239 char buf[32];
5240
5241 (void)ctxt;
5242 (void)argc;
5243 (void)args;
5244
5245 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5246 {
5247 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
5248 }
5249 else
5250 {
5251 grub_snprintf(buf, sizeof(buf), "0x0x0");
5252 }
5253
5254 grub_env_set(args[0], buf);
5255
5256 VENTOY_CMD_RETURN(0);
5257 }
5258
5259 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5260 {
5261 int id;
5262 char buf[32];
5263
5264 (void)ctxt;
5265 (void)argc;
5266
5267 if (!g_video_mode_list)
5268 {
5269 return 0;
5270 }
5271
5272 id = (int)grub_strtoul(args[0], NULL, 10);
5273 if (id < g_video_mode_num)
5274 {
5275 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5276 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5277 }
5278
5279 grub_env_set(args[1], buf);
5280
5281 VENTOY_CMD_RETURN(0);
5282 }
5283
5284 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5285 {
5286 grub_uint32_t i;
5287 grub_uint32_t loadsector = 0;
5288 grub_file_t file;
5289 char value[32];
5290 grub_uint32_t boot_catlog = 0;
5291 grub_uint8_t buf[512];
5292
5293 (void)ctxt;
5294
5295 if (argc != 2)
5296 {
5297 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5298 return 1;
5299 }
5300
5301 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5302 if (!file)
5303 {
5304 debug("failed to open %s\n", args[0]);
5305 return 1;
5306 }
5307
5308 boot_catlog = ventoy_get_iso_boot_catlog(file);
5309 if (boot_catlog == 0)
5310 {
5311 debug("No bootcatlog found\n");
5312 grub_file_close(file);
5313 return 1;
5314 }
5315
5316 grub_memset(buf, 0, sizeof(buf));
5317 grub_file_seek(file, boot_catlog * 2048);
5318 grub_file_read(file, buf, sizeof(buf));
5319 grub_file_close(file);
5320
5321 for (i = 0; i < sizeof(buf); i += 32)
5322 {
5323 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5324 {
5325 if (buf[i + 32] == 0x88)
5326 {
5327 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5328 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5329 break;
5330 }
5331 }
5332 }
5333
5334 if (loadsector == 0)
5335 {
5336 debug("No EFI eltorito info found\n");
5337 return 1;
5338 }
5339
5340 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5341 grub_env_set(args[1], value);
5342 VENTOY_CMD_RETURN(0);
5343 }
5344
5345 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5346 {
5347 int curpos;
5348 int printlen;
5349 grub_size_t len;
5350 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5351
5352 if (pfsdir->initrd[0])
5353 {
5354 return 1;
5355 }
5356
5357 curpos = pfsdir->curpos;
5358 len = grub_strlen(filename);
5359
5360 if (info->dir)
5361 {
5362 if ((len == 1 && filename[0] == '.') ||
5363 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5364 {
5365 return 0;
5366 }
5367
5368 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5369 pfsdir->dircnt++;
5370
5371 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5372 pfsdir->curpos = curpos + printlen;
5373 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5374 pfsdir->curpos = curpos;
5375 pfsdir->fullpath[curpos] = 0;
5376 }
5377 else
5378 {
5379 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5380 pfsdir->filecnt++;
5381
5382 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5383 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5384 {
5385 if (info->size > 32 * VTOY_SIZE_1MB)
5386 {
5387 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5388 return 1;
5389 }
5390 }
5391 }
5392
5393 return 0;
5394 }
5395
5396 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5397 {
5398 int i;
5399 char *pos = NULL;
5400 char *device_name = NULL;
5401 grub_device_t dev = NULL;
5402 grub_fs_t fs = NULL;
5403 replace_fs_dir *pfsdir = NULL;
5404
5405 (void)ctxt;
5406
5407 if (argc != 2)
5408 {
5409 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5410 return 1;
5411 }
5412
5413 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5414 if (!pfsdir)
5415 {
5416 return 1;
5417 }
5418
5419 device_name = grub_file_get_device_name(args[0]);
5420 if (!device_name)
5421 {
5422 goto fail;
5423 }
5424
5425 dev = grub_device_open(device_name);
5426 if (!dev)
5427 {
5428 goto fail;
5429 }
5430
5431 fs = grub_fs_probe(dev);
5432 if (!fs)
5433 {
5434 goto fail;
5435 }
5436
5437 pfsdir->dev = dev;
5438 pfsdir->fs = fs;
5439 pfsdir->curpos = 1;
5440 pfsdir->fullpath[0] = '/';
5441 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5442
5443 if (pfsdir->initrd[0])
5444 {
5445 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5446
5447 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5448 {
5449 if (pfsdir->initrd[i] == '/')
5450 {
5451 pfsdir->initrd[i] = '\\';
5452 }
5453 }
5454
5455 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5456 grub_env_set(args[1], pos);
5457 }
5458 else
5459 {
5460 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5461 }
5462
5463 fail:
5464
5465 grub_check_free(pfsdir);
5466 grub_check_free(device_name);
5467 check_free(dev, grub_device_close);
5468
5469 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5470 }
5471
5472 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5473 {
5474 const char *pager = NULL;
5475
5476 (void)ctxt;
5477 (void)argc;
5478 (void)args;
5479
5480 pager = grub_env_get("pager");
5481 if (NULL == pager)
5482 {
5483 g_pager_flag = 1;
5484 grub_env_set("pager", "1");
5485 }
5486 else if (pager[0] == '1')
5487 {
5488 g_pager_flag = 0;
5489 }
5490 else
5491 {
5492 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5493 g_pager_flag = 2;
5494 grub_env_set("pager", "1");
5495 }
5496
5497 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5498 }
5499
5500 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5501 {
5502 (void)ctxt;
5503 (void)argc;
5504 (void)args;
5505
5506 if (g_pager_flag == 1)
5507 {
5508 grub_env_unset("pager");
5509 }
5510 else if (g_pager_flag == 2)
5511 {
5512 grub_env_set("pager", g_old_pager);
5513 }
5514
5515 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5516 }
5517
5518 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5519 {
5520 if (g_json_case_mis_path[0])
5521 {
5522 return 1;
5523 }
5524
5525 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5526 {
5527 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5528 return 1;
5529 }
5530 return 0;
5531 }
5532
5533 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5534 {
5535 char path[16];
5536 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5537
5538 if (g_json_case_mis_path[0])
5539 {
5540 return 1;
5541 }
5542
5543 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5544 {
5545 if (grub_strcasecmp(filename, "ventoy") == 0)
5546 {
5547 grub_snprintf(path, sizeof(path), "/%s", filename);
5548 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5549 if (g_json_case_mis_path[0])
5550 {
5551 return 1;
5552 }
5553 }
5554 }
5555
5556 return 0;
5557 }
5558
5559 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5560 {
5561 int fstype = 0;
5562 char *device_name = NULL;
5563 grub_device_t dev = NULL;
5564 grub_fs_t fs = NULL;
5565 chk_case_fs_dir fs_dir;
5566
5567 (void)ctxt;
5568 (void)argc;
5569 (void)args;
5570
5571 device_name = grub_file_get_device_name(args[0]);
5572 if (!device_name)
5573 {
5574 goto out;
5575 }
5576
5577 dev = grub_device_open(device_name);
5578 if (!dev)
5579 {
5580 goto out;
5581 }
5582
5583 fs = grub_fs_probe(dev);
5584 if (!fs)
5585 {
5586 goto out;
5587 }
5588
5589 fstype = ventoy_get_fs_type(fs->name);
5590 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5591 {
5592 goto out;
5593 }
5594
5595 g_json_case_mis_path[0] = 0;
5596 fs_dir.dev = dev;
5597 fs_dir.fs = fs;
5598 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5599
5600 if (g_json_case_mis_path[0])
5601 {
5602 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5603 }
5604
5605 out:
5606
5607 grub_check_free(device_name);
5608 check_free(dev, grub_device_close);
5609
5610 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5611 }
5612
5613 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5614 {
5615 grub_disk_t disk;
5616 grub_partition_t part;
5617 char priority_str[3]; /* Maximum value 15 */
5618
5619 (void)ctxt;
5620
5621 if (argc < 2 || argc > 3)
5622 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5623 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5624
5625 /* Open the disk if it exists */
5626 disk = grub_disk_open (args[0]);
5627 if (!disk)
5628 {
5629 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5630 "Not a disk");
5631 }
5632
5633 part = grub_partition_probe (disk, args[1]);
5634 if (!part)
5635 {
5636 grub_disk_close (disk);
5637 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5638 "No such partition");
5639 }
5640
5641 if (grub_strcmp (part->partmap->name, "gpt"))
5642 {
5643 grub_disk_close (disk);
5644 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5645 "Not a GPT partition");
5646 }
5647
5648 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5649 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5650
5651 if (argc == 3)
5652 {
5653 grub_env_set (args[2], priority_str);
5654 grub_env_export (args[2]);
5655 }
5656 else
5657 {
5658 grub_printf ("Priority is %s\n", priority_str);
5659 }
5660
5661 grub_disk_close (disk);
5662 return GRUB_ERR_NONE;
5663 }
5664
5665
5666 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5667 {
5668 int ret = 1;
5669 int joliet = 0;
5670 grub_file_t file = NULL;
5671 grub_uint32_t loadrba = 0;
5672 grub_uint32_t boot_catlog = 0;
5673 grub_uint8_t sector[512];
5674 boot_info_table *info = NULL;
5675
5676 (void)ctxt;
5677 (void)argc;
5678
5679 /* This also trigger a iso9660 fs parse */
5680 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5681 {
5682 return 0;
5683 }
5684
5685 joliet = grub_iso9660_is_joliet();
5686 if (joliet == 0)
5687 {
5688 return 1;
5689 }
5690
5691 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5692 if (!file)
5693 {
5694 debug("failed to open %s\n", args[0]);
5695 return 1;
5696 }
5697
5698 boot_catlog = ventoy_get_iso_boot_catlog(file);
5699 if (boot_catlog == 0)
5700 {
5701 debug("no bootcatlog found %u\n", boot_catlog);
5702 goto out;
5703 }
5704
5705 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5706 if (loadrba == 0)
5707 {
5708 debug("no bios eltorito rba found %u\n", loadrba);
5709 goto out;
5710 }
5711
5712 grub_file_seek(file, loadrba * 2048);
5713 grub_file_read(file, sector, 512);
5714
5715 info = (boot_info_table *)sector;
5716 if (info->bi_data0 == 0x7c6ceafa &&
5717 info->bi_data1 == 0x90900000 &&
5718 info->bi_PrimaryVolumeDescriptor == 16 &&
5719 info->bi_BootFileLocation == loadrba)
5720 {
5721 debug("bootloader is syslinux, %u.\n", loadrba);
5722 ret = 0;
5723 }
5724
5725 out:
5726
5727 grub_file_close(file);
5728 grub_errno = GRUB_ERR_NONE;
5729 return ret;
5730 }
5731
5732 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5733 {
5734 int n = 0;
5735 ventoy_vlnk_part *node;
5736
5737 (void)ctxt;
5738 (void)argc;
5739 (void)args;
5740
5741 for (node = g_vlnk_part_list; node; node = node->next)
5742 {
5743 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5744 ++n, node->device, node->disksig,
5745 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5746 }
5747
5748 return 0;
5749 }
5750
5751 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5752 {
5753 int len = 0;
5754
5755 (void)ctxt;
5756
5757 if (argc == 1)
5758 {
5759 len = (int)grub_strlen(args[0]);
5760 if (grub_file_is_vlnk_suffix(args[0], len))
5761 {
5762 return 0;
5763 }
5764 }
5765
5766 return 1;
5767 }
5768
5769 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5770 {
5771 int vlnk = 0;
5772 const char *name = NULL;
5773
5774 (void)ctxt;
5775
5776 if (argc == 2)
5777 {
5778 grub_env_unset(args[1]);
5779 name = grub_file_get_vlnk(args[0], &vlnk);
5780 if (vlnk)
5781 {
5782 debug("VLNK SRC: <%s>\n", args[0]);
5783 debug("VLNK DST: <%s>\n", name);
5784 grub_env_set(args[1], name);
5785 return 0;
5786 }
5787 }
5788
5789 return 1;
5790 }
5791
5792 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5793 {
5794 int ret = 1;
5795 int len = 0;
5796 grub_file_t file = NULL;
5797 ventoy_vlnk vlnk;
5798 char dst[512];
5799
5800 (void)ctxt;
5801
5802 if (argc != 1)
5803 {
5804 goto out;
5805 }
5806
5807 len = (int)grub_strlen(args[0]);
5808 if (!grub_file_is_vlnk_suffix(args[0], len))
5809 {
5810 grub_printf("Invalid vlnk suffix\n");
5811 goto out;
5812 }
5813
5814 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5815 if (!file)
5816 {
5817 grub_printf("Failed to open %s\n", args[0]);
5818 goto out;
5819 }
5820
5821 if (file->size != 32768)
5822 {
5823 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5824 goto out;
5825 }
5826
5827 grub_memset(&vlnk, 0, sizeof(vlnk));
5828 grub_file_read(file, &vlnk, sizeof(vlnk));
5829
5830 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5831
5832 out:
5833
5834 grub_refresh();
5835 check_free(file, grub_file_close);
5836 grub_errno = GRUB_ERR_NONE;
5837 return ret;
5838 }
5839
5840 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5841 {
5842 (void)ctxt;
5843 (void)argc;
5844 (void)args;
5845
5846 g_iso_vd_id_publisher[0] = 0;
5847 g_iso_vd_id_prepare[0] = 0;
5848 g_iso_vd_id_application[0] = 0;
5849
5850 return 0;
5851 }
5852
5853 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
5854 {
5855 int ret = 1;
5856 int offset = 318;
5857 grub_file_t file = NULL;
5858
5859 (void)ctxt;
5860 (void)argc;
5861
5862 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5863 if (!file)
5864 {
5865 grub_printf("Failed to open %s\n", args[0]);
5866 goto out;
5867 }
5868
5869 grub_file_seek(file, 16 * 2048 + offset);
5870 grub_file_read(file, g_iso_vd_id_publisher, 128);
5871
5872 offset += 128;
5873 grub_file_seek(file, 16 * 2048 + offset);
5874 grub_file_read(file, g_iso_vd_id_prepare, 128);
5875
5876 offset += 128;
5877 grub_file_seek(file, 16 * 2048 + offset);
5878 grub_file_read(file, g_iso_vd_id_application, 128);
5879
5880 out:
5881
5882 check_free(file, grub_file_close);
5883 grub_errno = GRUB_ERR_NONE;
5884 return ret;
5885 }
5886
5887 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
5888 {
5889 int ret = 1;
5890 char *id = g_iso_vd_id_publisher;
5891
5892 (void)ctxt;
5893 (void)argc;
5894
5895 if (args[0][0] == '1')
5896 {
5897 id = g_iso_vd_id_prepare;
5898 }
5899 else if (args[0][0] == '2')
5900 {
5901 id = g_iso_vd_id_application;
5902 }
5903
5904 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
5905 {
5906 ret = 0;
5907 }
5908
5909 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
5910 {
5911 ret = 0;
5912 }
5913
5914 grub_errno = GRUB_ERR_NONE;
5915 return ret;
5916 }
5917
5918 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
5919 {
5920 (void)ctxt;
5921 (void)argc;
5922
5923 g_ventoy_fn_mutex = 0;
5924 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
5925 {
5926 g_ventoy_fn_mutex = 1;
5927 }
5928
5929 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5930 }
5931
5932 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
5933 {
5934 grub_uint64_t total;
5935 grub_uint64_t org_required;
5936 grub_uint64_t new_required;
5937
5938 (void)ctxt;
5939 (void)argc;
5940 (void)args;
5941
5942 #ifdef GRUB_MACHINE_EFI
5943 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
5944 grub_printf("Total pages: %llu\n", (unsigned long long)total);
5945 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
5946 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
5947 #else
5948 (void)total;
5949 (void)org_required;
5950 (void)new_required;
5951 grub_printf("Non EFI mode!\n");
5952 #endif
5953
5954 grub_refresh();
5955
5956 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5957 }
5958
5959 int ventoy_env_init(void)
5960 {
5961 int i;
5962 char buf[64];
5963
5964 grub_env_set("vtdebug_flag", "");
5965
5966 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
5967 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5968 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5969 for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++)
5970 {
5971 g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size);
5972 }
5973
5974 ventoy_filt_register(0, ventoy_wrapper_open);
5975
5976 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
5977 if (g_grub_param)
5978 {
5979 g_grub_param->grub_env_get = grub_env_get;
5980 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5981 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5982 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5983 grub_env_set("env_param", buf);
5984 grub_env_set("ventoy_env_param", buf);
5985
5986 grub_env_export("env_param");
5987 grub_env_export("ventoy_env_param");
5988 }
5989
5990 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5991 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5992
5993 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5994 grub_env_set("vtoy_winpeshl_ini_size", buf);
5995
5996 grub_env_export("vtoy_winpeshl_ini_addr");
5997 grub_env_export("vtoy_winpeshl_ini_size");
5998
5999 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
6000 grub_env_set("vtoy_chain_file_size", buf);
6001 grub_env_export("vtoy_chain_file_size");
6002
6003 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
6004 grub_env_set("vtoy_chain_file_read", buf);
6005 grub_env_export("vtoy_chain_file_read");
6006
6007 return 0;
6008 }
6009
6010
6011
6012 static cmd_para ventoy_cmds[] =
6013 {
6014 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
6015 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
6016 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
6017 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
6018 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
6019 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
6020 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
6021 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6022 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6023 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
6024 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
6025 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
6026 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
6027 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
6028 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
6029 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
6030 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
6031 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
6032 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
6033 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
6034 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
6035 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
6036 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
6037 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
6038 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
6039 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
6040 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
6041
6042 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
6043 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
6044 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
6045 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
6046 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
6047 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
6048 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
6049
6050 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
6051 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
6052 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
6053 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
6054 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
6055 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
6056 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
6057 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
6058 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
6059 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
6060
6061
6062 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
6063 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
6064 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
6065 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
6066 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
6067 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
6068 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
6069 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
6070 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
6071 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
6072 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
6073
6074 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
6075 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
6076 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
6077 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
6078 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
6079 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
6080 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
6081
6082 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6083 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6084 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
6085 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
6086 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
6087 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
6088 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
6089 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
6090 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
6091 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
6092
6093 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
6094 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
6095 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
6096 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
6097 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
6098 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
6099 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
6100 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
6101 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
6102
6103 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
6104 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
6105 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
6106 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
6107
6108
6109 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
6110 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
6111 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
6112
6113 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
6114 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
6115 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
6116
6117
6118 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
6119 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
6120 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
6121 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
6122 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
6123 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
6124 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
6125 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
6126 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
6127 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
6128 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
6129 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
6130 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
6131 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
6132
6133 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
6134 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
6135 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
6136 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
6137 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
6138 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
6139 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
6140 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
6141 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
6142 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
6143 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
6144 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
6145
6146 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
6147 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
6148 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
6149 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
6150 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
6151 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
6152 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
6153 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
6154 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
6155 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
6156 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
6157 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
6158 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
6159 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
6160 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
6161 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
6162 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
6163 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
6164 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
6165 };
6166
6167 int ventoy_register_all_cmd(void)
6168 {
6169 grub_uint32_t i;
6170 cmd_para *cur = NULL;
6171
6172 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6173 {
6174 cur = ventoy_cmds + i;
6175 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
6176 cur->summary, cur->description, cur->parser);
6177 }
6178
6179 return 0;
6180 }
6181
6182 int ventoy_unregister_all_cmd(void)
6183 {
6184 grub_uint32_t i;
6185
6186 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6187 {
6188 grub_unregister_extcmd(ventoy_cmds[i].cmd);
6189 }
6190
6191 return 0;
6192 }
6193
6194