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