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