]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
c2c4799cdc3ff58a14b06df24909f607c9a77ffa
[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
3767 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3768 grub_script_execute_sourcecode(configfile);
3769
3770 g_ventoy_menu_esc = 0;
3771 g_ventoy_suppress_esc = 0;
3772 g_ventoy_suppress_esc_default = 1;
3773
3774 grub_free(buf);
3775
3776 node->cursel = g_ventoy_last_entry - 1;
3777
3778 load:
3779 grub_check_free(node->filebuf);
3780 node->filelen = 0;
3781
3782 if (node->cursel >= 0 && node->cursel < node->templatenum)
3783 {
3784 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"),
3785 node->templatepath[node->cursel].path);
3786 if (file)
3787 {
3788 node->filebuf = grub_malloc(file->size + 8);
3789 if (node->filebuf)
3790 {
3791 grub_file_read(file, node->filebuf, file->size);
3792 grub_file_close(file);
3793
3794 grub_memset(node->filebuf + file->size, 0, 8);
3795 node->filelen = (int)file->size;
3796
3797 ventoy_auto_install_var_expand(node);
3798 }
3799 }
3800 else
3801 {
3802 debug("Failed to open auto install script <%s%s>\n",
3803 ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path);
3804 }
3805 }
3806
3807 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3808 }
3809
3810 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3811 {
3812 int i = 0;
3813 int pos = 0;
3814 int defidx = 1;
3815 char *buf = NULL;
3816 char configfile[128];
3817 persistence_config *node;
3818
3819 (void)ctxt;
3820 (void)argc;
3821 (void)args;
3822
3823 debug("select persistence argc:%d\n", argc);
3824
3825 if (argc < 1)
3826 {
3827 return 0;
3828 }
3829
3830 node = ventoy_plugin_find_persistent(args[0]);
3831 if (!node)
3832 {
3833 debug("Persistence image not found for %s\n", args[0]);
3834 return 0;
3835 }
3836
3837 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3838 {
3839 defidx = node->autosel;
3840 if (node->timeout < 0)
3841 {
3842 node->cursel = node->autosel - 1;
3843 debug("Persistence image auto select %d\n", node->autosel);
3844 return 0;
3845 }
3846 }
3847
3848 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3849 if (!buf)
3850 {
3851 return 0;
3852 }
3853
3854 if (node->timeout > 0)
3855 {
3856 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3857 }
3858
3859 vtoy_ssprintf(buf, pos, "menuentry \"$VTLANG_NO_PERSISTENCE\" --class=\"sel_persistence\" {\n"
3860 " echo %s\n}\n", "");
3861
3862 for (i = 0; i < node->backendnum; i++)
3863 {
3864 vtoy_ssprintf(buf, pos, "menuentry \"%s %s\" --class=\"sel_persistence\" {\n"
3865 " echo \"\"\n}\n",
3866 ventoy_get_vmenu_title("VTLANG_PERSIST_USE"),
3867 node->backendpath[i].path);
3868
3869 }
3870
3871 g_ventoy_menu_esc = 1;
3872 g_ventoy_suppress_esc = 1;
3873 g_ventoy_suppress_esc_default = defidx;
3874
3875 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3876 grub_script_execute_sourcecode(configfile);
3877
3878 g_ventoy_menu_esc = 0;
3879 g_ventoy_suppress_esc = 0;
3880 g_ventoy_suppress_esc_default = 1;
3881
3882 grub_free(buf);
3883
3884 node->cursel = g_ventoy_last_entry - 1;
3885
3886 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3887 }
3888
3889 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3890 {
3891 grub_uint32_t i;
3892 ventoy_img_chunk *cur;
3893
3894 (void)ctxt;
3895 (void)argc;
3896 (void)args;
3897
3898 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3899 {
3900 cur = g_img_chunk_list.chunk + i;
3901 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3902 cur->img_start_sector, cur->img_end_sector,
3903 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3904 );
3905 }
3906
3907 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3908 }
3909
3910 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3911 {
3912 grub_uint32_t i;
3913 grub_file_t file;
3914 ventoy_img_chunk_list chunklist;
3915
3916 (void)ctxt;
3917 (void)argc;
3918
3919 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3920 if (!file)
3921 {
3922 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3923 }
3924
3925 /* get image chunk data */
3926 grub_memset(&chunklist, 0, sizeof(chunklist));
3927 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3928 if (NULL == chunklist.chunk)
3929 {
3930 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3931 }
3932
3933 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3934 chunklist.cur_chunk = 0;
3935
3936 ventoy_get_block_list(file, &chunklist, 0);
3937
3938 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3939 {
3940 grub_printf("########## UNSUPPORTED ###############\n");
3941 }
3942
3943 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3944
3945 for (i = 0; i < chunklist.cur_chunk; i++)
3946 {
3947 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3948 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3949 }
3950
3951 grub_printf("\n==================================\n");
3952
3953 for (i = 0; i < chunklist.cur_chunk; i++)
3954 {
3955 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3956 (ulonglong)chunklist.chunk[i].img_start_sector,
3957 (ulonglong)chunklist.chunk[i].img_end_sector,
3958 (ulonglong)chunklist.chunk[i].disk_start_sector,
3959 (ulonglong)chunklist.chunk[i].disk_end_sector
3960 );
3961 }
3962
3963 grub_free(chunklist.chunk);
3964 grub_file_close(file);
3965
3966 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3967 }
3968
3969 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3970 {
3971 int i;
3972 ventoy_grub_param_file_replace *replace = NULL;
3973
3974 (void)ctxt;
3975 (void)argc;
3976 (void)args;
3977
3978 if (argc >= 2)
3979 {
3980 replace = &(g_grub_param->file_replace);
3981 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3982
3983 replace->old_name_cnt = 0;
3984 for (i = 0; i < 4 && i + 1 < argc; i++)
3985 {
3986 replace->old_name_cnt++;
3987 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3988 }
3989
3990 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3991 }
3992
3993 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3994 }
3995
3996 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3997 {
3998 char buf[32];
3999 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
4000
4001 (void)ctxt;
4002
4003 if (argc >= 1)
4004 {
4005 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
4006 grub_env_set(args[0], buf);
4007 }
4008
4009 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4010 }
4011
4012 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
4013 {
4014 (void)ctxt;
4015 (void)argc;
4016 (void)args;
4017
4018 if (argc == 0)
4019 {
4020 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
4021 grub_printf("%s", g_list_script_buf);
4022 }
4023 else
4024 {
4025 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
4026 grub_printf("%s", g_tree_script_buf);
4027 }
4028
4029 return 0;
4030 }
4031
4032 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
4033 {
4034 img_info *cur = g_ventoy_img_list;
4035
4036 (void)ctxt;
4037 (void)argc;
4038 (void)args;
4039
4040 while (cur)
4041 {
4042 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
4043 grub_printf("name:<%s>\n\n", cur->name);
4044 cur = cur->next;
4045 }
4046
4047 return 0;
4048 }
4049
4050 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
4051 {
4052 (void)ctxt;
4053 (void)argc;
4054 (void)args;
4055
4056 ventoy_plugin_dump_injection();
4057
4058 return 0;
4059 }
4060
4061 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
4062 {
4063 (void)ctxt;
4064 (void)argc;
4065 (void)args;
4066
4067 ventoy_plugin_dump_auto_install();
4068
4069 return 0;
4070 }
4071
4072 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
4073 {
4074 (void)ctxt;
4075 (void)argc;
4076 (void)args;
4077
4078 ventoy_plugin_dump_persistence();
4079
4080 return 0;
4081 }
4082
4083 static int ventoy_check_mode_by_name(char *filename, const char *suffix)
4084 {
4085 int i;
4086 int len1;
4087 int len2;
4088
4089 len1 = (int)grub_strlen(filename);
4090 len2 = (int)grub_strlen(suffix);
4091
4092 if (len1 <= len2)
4093 {
4094 return 0;
4095 }
4096
4097 for (i = len1 - 1; i >= 0; i--)
4098 {
4099 if (filename[i] == '.')
4100 {
4101 break;
4102 }
4103 }
4104
4105 if (i < len2 + 1)
4106 {
4107 return 0;
4108 }
4109
4110 if (filename[i - len2 - 1] != '_')
4111 {
4112 return 0;
4113 }
4114
4115 if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0)
4116 {
4117 return 1;
4118 }
4119
4120 return 0;
4121 }
4122
4123 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4124 {
4125 (void)ctxt;
4126 (void)argc;
4127 (void)args;
4128
4129 if (argc != 1 && argc != 2)
4130 {
4131 return 1;
4132 }
4133
4134 if (args[0][0] == '0')
4135 {
4136 if (g_ventoy_memdisk_mode)
4137 {
4138 return 0;
4139 }
4140
4141 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk"))
4142 {
4143 return 0;
4144 }
4145
4146 return 1;
4147 }
4148 else if (args[0][0] == '1')
4149 {
4150 return g_ventoy_iso_raw ? 0 : 1;
4151 }
4152 else if (args[0][0] == '2')
4153 {
4154 return g_ventoy_iso_uefi_drv ? 0 : 1;
4155 }
4156 else if (args[0][0] == '3')
4157 {
4158 if (g_ventoy_grub2_mode)
4159 {
4160 return 0;
4161 }
4162
4163 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2"))
4164 {
4165 return 0;
4166 }
4167
4168 return 1;
4169 }
4170 else if (args[0][0] == '4')
4171 {
4172 if (g_ventoy_wimboot_mode)
4173 {
4174 return 0;
4175 }
4176
4177 if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot"))
4178 {
4179 return 0;
4180 }
4181
4182 return 1;
4183 }
4184
4185 return 1;
4186 }
4187
4188 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
4189 {
4190 static int configfile_mode = 0;
4191 char memfile[128] = {0};
4192
4193 (void)ctxt;
4194 (void)argc;
4195 (void)args;
4196
4197 /*
4198 * args[0]: 0:normal 1:configfile
4199 * args[1]: 0:list_buf 1:tree_buf
4200 */
4201
4202 if (argc != 2)
4203 {
4204 debug("Invalid argc %d\n", argc);
4205 return 0;
4206 }
4207
4208 VTOY_CMD_CHECK(1);
4209
4210 if (args[0][0] == '0')
4211 {
4212 if (args[1][0] == '0')
4213 {
4214 grub_script_execute_sourcecode(g_list_script_buf);
4215 }
4216 else
4217 {
4218 grub_script_execute_sourcecode(g_tree_script_buf);
4219 }
4220 }
4221 else
4222 {
4223 if (configfile_mode)
4224 {
4225 debug("Now already in F3 mode %d\n", configfile_mode);
4226 return 0;
4227 }
4228
4229 if (args[1][0] == '0')
4230 {
4231 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4232 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
4233 }
4234 else
4235 {
4236 g_ventoy_last_entry = -1;
4237 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
4238 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
4239 }
4240
4241 configfile_mode = 1;
4242 grub_script_execute_sourcecode(memfile);
4243 configfile_mode = 0;
4244 }
4245
4246 return 0;
4247 }
4248
4249 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
4250 {
4251 grub_file_t file;
4252
4253 (void)ctxt;
4254
4255 if (argc != 1)
4256 {
4257 return 1;
4258 }
4259
4260 g_ventoy_case_insensitive = 1;
4261 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4262 g_ventoy_case_insensitive = 0;
4263
4264 grub_errno = 0;
4265
4266 if (file)
4267 {
4268 grub_file_close(file);
4269 return 0;
4270 }
4271 return 1;
4272 }
4273
4274 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
4275 {
4276 int id = 0;
4277 int find = 0;
4278 grub_disk_t disk;
4279 const char *isopath = NULL;
4280 char hdname[32];
4281 ventoy_mbr_head mbr;
4282
4283 (void)ctxt;
4284 (void)argc;
4285
4286 if (argc != 1)
4287 {
4288 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
4289 }
4290
4291 isopath = grub_env_get("vtoy_iso_part");
4292 if (!isopath)
4293 {
4294 debug("isopath is null %p\n", isopath);
4295 return 0;
4296 }
4297
4298 debug("isopath is %s\n", isopath);
4299
4300 for (id = 0; id < 30 && (find == 0); id++)
4301 {
4302 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
4303 if (grub_strstr(isopath, hdname))
4304 {
4305 debug("skip %s ...\n", hdname);
4306 continue;
4307 }
4308
4309 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
4310
4311 disk = grub_disk_open(hdname);
4312 if (!disk)
4313 {
4314 debug("%s not exist\n", hdname);
4315 break;
4316 }
4317
4318 grub_memset(&mbr, 0, sizeof(mbr));
4319 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
4320 {
4321 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
4322 {
4323 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
4324 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
4325 {
4326
4327 grub_env_set(args[0], hdname);
4328 find = 1;
4329 }
4330 }
4331 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
4332 }
4333 else
4334 {
4335 debug("read %s failed\n", hdname);
4336 }
4337
4338 grub_disk_close(disk);
4339 }
4340
4341 return 0;
4342 }
4343
4344 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
4345 {
4346 int len = 1024;
4347 grub_file_t file;
4348 char *buf = NULL;
4349
4350 (void)ctxt;
4351 (void)argc;
4352
4353 if (argc != 2)
4354 {
4355 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
4356 }
4357
4358 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4359 if (!file)
4360 {
4361 debug("failed to open file %s\n", args[0]);
4362 return 0;
4363 }
4364
4365 buf = grub_malloc(len);
4366 if (!buf)
4367 {
4368 goto end;
4369 }
4370
4371 buf[len - 1] = 0;
4372 grub_file_read(file, buf, len - 1);
4373
4374 ventoy_get_line(buf);
4375 ventoy_set_env(args[1], buf);
4376
4377 end:
4378
4379 grub_check_free(buf);
4380 grub_file_close(file);
4381
4382 return 0;
4383 }
4384
4385 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
4386 {
4387 grub_uint64_t end_max = 0;
4388 int *pCnt = (int *)data;
4389
4390 (void)disk;
4391
4392 (*pCnt)++;
4393 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
4394 "0 %llu linear /dev/ventoy %llu\n",
4395 (ulonglong)partition->len, (ulonglong)partition->start);
4396
4397 end_max = (partition->len + partition->start) * 512;
4398 if (end_max > g_part_end_max)
4399 {
4400 g_part_end_max = end_max;
4401 }
4402
4403 return 0;
4404 }
4405
4406 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
4407 {
4408 int cnt = 0;
4409 char *device_name = NULL;
4410 grub_device_t dev = NULL;
4411 char buf[64];
4412
4413 (void)ctxt;
4414
4415 g_part_list_pos = 0;
4416 g_part_end_max = 0;
4417 grub_env_unset("vtoy_img_part_file");
4418
4419 if (argc != 1)
4420 {
4421 return 1;
4422 }
4423
4424 device_name = grub_file_get_device_name(args[0]);
4425 if (!device_name)
4426 {
4427 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
4428 goto end;
4429 }
4430
4431 dev = grub_device_open(device_name);
4432 if (!dev)
4433 {
4434 debug("grub_device_open failed, %s\n", device_name);
4435 goto end;
4436 }
4437
4438 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
4439
4440 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
4441 grub_env_set("vtoy_img_part_file", buf);
4442
4443 grub_snprintf(buf, sizeof(buf), "%d", cnt);
4444 grub_env_set("vtoy_img_part_cnt", buf);
4445
4446 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max);
4447 grub_env_set("vtoy_img_max_part_end", buf);
4448
4449 end:
4450
4451 check_free(device_name, grub_free);
4452 check_free(dev, grub_device_close);
4453
4454 return 0;
4455 }
4456
4457
4458 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
4459 {
4460 int rc = 1;
4461 grub_file_t file;
4462 char *buf = NULL;
4463
4464 (void)ctxt;
4465 (void)argc;
4466
4467 if (argc != 2)
4468 {
4469 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
4470 }
4471
4472 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4473 if (!file)
4474 {
4475 debug("failed to open file %s\n", args[0]);
4476 return 1;
4477 }
4478
4479 buf = grub_malloc(file->size + 1);
4480 if (!buf)
4481 {
4482 goto end;
4483 }
4484
4485 buf[file->size] = 0;
4486 grub_file_read(file, buf, file->size);
4487
4488 if (grub_strstr(buf, args[1]))
4489 {
4490 rc = 0;
4491 }
4492
4493 end:
4494
4495 grub_check_free(buf);
4496 grub_file_close(file);
4497
4498 return rc;
4499 }
4500
4501 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
4502 {
4503 int len;
4504 grub_file_t file;
4505 char buf[64];
4506 grub_uint64_t size;
4507 ventoy_iso9660_vd pvd;
4508
4509 (void)ctxt;
4510 (void)argc;
4511
4512 if (argc != 4)
4513 {
4514 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
4515 }
4516
4517 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4518 if (!file)
4519 {
4520 debug("failed to open file %s\n", args[0]);
4521 return 0;
4522 }
4523
4524 grub_file_seek(file, 16 * 2048);
4525 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
4526 if (len != sizeof(pvd))
4527 {
4528 debug("failed to read pvd %d\n", len);
4529 goto end;
4530 }
4531
4532 grub_memset(buf, 0, sizeof(buf));
4533 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
4534 ventoy_set_env(args[1], buf);
4535
4536 grub_memset(buf, 0, sizeof(buf));
4537 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
4538 ventoy_set_env(args[2], buf);
4539
4540 size = pvd.space;
4541 size *= 2048;
4542 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
4543 ventoy_set_env(args[3], buf);
4544
4545 end:
4546 grub_file_close(file);
4547
4548 return 0;
4549 }
4550
4551 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
4552 {
4553 int len;
4554 grub_file_t file;
4555 char buf[64];
4556
4557 (void)ctxt;
4558 (void)argc;
4559
4560 if (argc != 2)
4561 {
4562 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
4563 }
4564
4565 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4566 if (!file)
4567 {
4568 debug("failed to open file %s\n", args[0]);
4569 return 0;
4570 }
4571
4572 grub_memset(buf, 0, sizeof(buf));
4573 grub_file_seek(file, 16 * 2048 + 813);
4574 len = (int)grub_file_read(file, buf, 17);
4575 if (len != 17)
4576 {
4577 debug("failed to read create date %d\n", len);
4578 goto end;
4579 }
4580
4581 ventoy_set_env(args[1], buf);
4582
4583 end:
4584 grub_file_close(file);
4585
4586 return 0;
4587 }
4588
4589 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4590 {
4591 (void)ctxt;
4592 (void)argc;
4593 (void)args;
4594
4595 ventoy_env_hook_root(1);
4596
4597 return 0;
4598 }
4599
4600 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
4601 {
4602 (void)ctxt;
4603 (void)argc;
4604 (void)args;
4605
4606 ventoy_env_hook_root(0);
4607
4608 return 0;
4609 }
4610
4611 #ifdef GRUB_MACHINE_EFI
4612 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4613 {
4614 int ret = 1;
4615 grub_uint8_t *var;
4616 grub_size_t size;
4617 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4618
4619 (void)ctxt;
4620 (void)argc;
4621 (void)args;
4622
4623 var = grub_efi_get_variable("SecureBoot", &global, &size);
4624 if (var && *var == 1)
4625 {
4626 return 0;
4627 }
4628
4629 return ret;
4630 }
4631 #else
4632 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
4633 {
4634 (void)ctxt;
4635 (void)argc;
4636 (void)args;
4637 return 1;
4638 }
4639 #endif
4640
4641 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
4642 {
4643 int i;
4644 int ret = 1;
4645 grub_file_t file;
4646 grub_uint64_t FileSectors = 0;
4647 ventoy_gpt_info *gpt = NULL;
4648 ventoy_part_table *pt = NULL;
4649 grub_uint8_t zeroguid[16] = {0};
4650
4651 (void)ctxt;
4652 (void)argc;
4653
4654 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
4655 if (!file)
4656 {
4657 debug("failed to open file %s\n", args[0]);
4658 return 1;
4659 }
4660
4661 if (file->size % 512)
4662 {
4663 debug("unaligned file size: %llu\n", (ulonglong)file->size);
4664 goto out;
4665 }
4666
4667 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
4668 if (!gpt)
4669 {
4670 goto out;
4671 }
4672
4673 FileSectors = file->size / 512;
4674
4675 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
4676 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
4677 {
4678 debug("This is EFI partition table\n");
4679
4680 for (i = 0; i < 128; i++)
4681 {
4682 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
4683 {
4684 if (FileSectors < gpt->PartTbl[i].LastLBA)
4685 {
4686 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4687 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
4688 goto out;
4689 }
4690 }
4691 }
4692 }
4693 else
4694 {
4695 debug("This is MBR partition table\n");
4696
4697 for (i = 0; i < 4; i++)
4698 {
4699 pt = gpt->MBR.PartTbl + i;
4700 if (FileSectors < pt->StartSectorId + pt->SectorCount)
4701 {
4702 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
4703 (ulonglong)(pt->StartSectorId + pt->SectorCount),
4704 (ulonglong)FileSectors);
4705 goto out;
4706 }
4707 }
4708 }
4709
4710 ret = 0;
4711
4712 out:
4713 grub_file_close(file);
4714 grub_check_free(gpt);
4715 grub_errno = GRUB_ERR_NONE;
4716 return ret;
4717 }
4718
4719 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
4720 {
4721 int i;
4722 int ret;
4723
4724 (void)ctxt;
4725 (void)argc;
4726 (void)args;
4727
4728 for (i = 0; i < 500; i++)
4729 {
4730 ret = grub_getkey_noblock();
4731 if (ret == GRUB_TERM_NO_KEY)
4732 {
4733 break;
4734 }
4735 }
4736
4737 if (i >= 500)
4738 {
4739 grub_cls();
4740 grub_printf("\n\n Still have key input after clear.\n");
4741 grub_refresh();
4742 grub_sleep(5);
4743 }
4744
4745 return 0;
4746 }
4747
4748 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4749 {
4750 int i;
4751 int buflen;
4752 int datalen;
4753 int loclen;
4754 int img_chunk_num;
4755 int image_sector_size;
4756 char cmd[64];
4757 ventoy_chain_head *chain;
4758 ventoy_img_chunk *chunk;
4759 ventoy_os_param *osparam;
4760 ventoy_image_location *location;
4761 ventoy_image_disk_region *region;
4762 struct grub_acpi_table_header *acpi;
4763
4764 (void)ctxt;
4765
4766 if (argc != 2)
4767 {
4768 return 1;
4769 }
4770
4771 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4772
4773 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4774 if (!chain)
4775 {
4776 return 1;
4777 }
4778
4779 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4780
4781 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4782 {
4783 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4784 return 1;
4785 }
4786
4787 img_chunk_num = chain->img_chunk_num;
4788
4789 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4790 datalen = sizeof(ventoy_os_param) + loclen;
4791
4792 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4793 acpi = grub_zalloc(buflen);
4794 if (!acpi)
4795 {
4796 return 1;
4797 }
4798
4799 /* Step1: Fill acpi table header */
4800 grub_memcpy(acpi->signature, "VTOY", 4);
4801 acpi->length = buflen;
4802 acpi->revision = 1;
4803 grub_memcpy(acpi->oemid, "VENTOY", 6);
4804 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4805 acpi->oemrev = 1;
4806 acpi->creator_id[0] = 1;
4807 acpi->creator_rev = 1;
4808
4809 /* Step2: Fill data */
4810 osparam = (ventoy_os_param *)(acpi + 1);
4811 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4812 osparam->vtoy_img_location_addr = 0;
4813 osparam->vtoy_img_location_len = loclen;
4814 osparam->chksum = 0;
4815 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4816
4817 location = (ventoy_image_location *)(osparam + 1);
4818 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4819 location->image_sector_size = image_sector_size;
4820 location->disk_sector_size = chain->disk_sector_size;
4821 location->region_count = img_chunk_num;
4822
4823 region = location->regions;
4824 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4825 if (512 == image_sector_size)
4826 {
4827 for (i = 0; i < img_chunk_num; i++)
4828 {
4829 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4830 region->image_start_sector = chunk->img_start_sector * 4;
4831 region->disk_start_sector = chunk->disk_start_sector;
4832 region++;
4833 chunk++;
4834 }
4835 }
4836 else
4837 {
4838 for (i = 0; i < img_chunk_num; i++)
4839 {
4840 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4841 region->image_start_sector = chunk->img_start_sector;
4842 region->disk_start_sector = chunk->disk_start_sector;
4843 region++;
4844 chunk++;
4845 }
4846 }
4847
4848 /* Step3: Fill acpi checksum */
4849 acpi->checksum = 0;
4850 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4851
4852 /* load acpi table */
4853 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4854 grub_script_execute_sourcecode(cmd);
4855
4856 grub_free(acpi);
4857
4858 VENTOY_CMD_RETURN(0);
4859 }
4860
4861 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4862 {
4863 (void)ctxt;
4864 (void)argc;
4865 (void)args;
4866
4867 g_ventoy_last_entry_back = g_ventoy_last_entry;
4868 g_ventoy_last_entry = -1;
4869
4870 return 0;
4871 }
4872
4873 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4874 {
4875 (void)ctxt;
4876 (void)argc;
4877 (void)args;
4878
4879 g_ventoy_last_entry = g_ventoy_last_entry_back;
4880
4881 return 0;
4882 }
4883
4884 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4885 {
4886 const char *pos = filename + 1;
4887
4888 if (info->dir)
4889 {
4890 while (*pos)
4891 {
4892 if (*pos == '.')
4893 {
4894 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4895 {
4896 grub_strncpy((char *)data, filename, 128);
4897 return 1;
4898 }
4899 }
4900 pos++;
4901 }
4902 }
4903
4904 return 0;
4905 }
4906
4907 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4908 {
4909 int rc = 1;
4910 char *device_name = NULL;
4911 grub_device_t dev = NULL;
4912 grub_fs_t fs = NULL;
4913 char buf[128] = {0};
4914
4915 (void)ctxt;
4916
4917 if (argc != 3)
4918 {
4919 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4920 return 1;
4921 }
4922
4923 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4924
4925 device_name = grub_file_get_device_name(args[0]);
4926 if (!device_name)
4927 {
4928 debug("grub_file_get_device_name failed, %s\n", args[0]);
4929 goto end;
4930 }
4931
4932 dev = grub_device_open(device_name);
4933 if (!dev)
4934 {
4935 debug("grub_device_open failed, %s\n", device_name);
4936 goto end;
4937 }
4938
4939 fs = grub_fs_probe(dev);
4940 if (!fs)
4941 {
4942 debug("grub_fs_probe failed, %s\n", device_name);
4943 goto end;
4944 }
4945
4946 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4947
4948 if (buf[0])
4949 {
4950 ventoy_set_env(args[2], buf);
4951 }
4952
4953 rc = 0;
4954
4955 end:
4956
4957 check_free(device_name, grub_free);
4958 check_free(dev, grub_device_close);
4959
4960 return rc;
4961 }
4962
4963 int ventoy_load_part_table(const char *diskname)
4964 {
4965 char name[64];
4966 int ret;
4967 grub_disk_t disk;
4968 grub_device_t dev;
4969
4970 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4971 if (!g_ventoy_part_info)
4972 {
4973 return 1;
4974 }
4975
4976 disk = grub_disk_open(diskname);
4977 if (!disk)
4978 {
4979 debug("Failed to open disk %s\n", diskname);
4980 return 1;
4981 }
4982
4983 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4984
4985 g_ventoy_disk_bios_id = disk->id;
4986
4987 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4988 grub_disk_close(disk);
4989
4990 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4991 dev = grub_device_open(name);
4992 if (dev)
4993 {
4994 /* Check for official Ventoy device */
4995 ret = ventoy_check_official_device(dev);
4996 grub_device_close(dev);
4997
4998 if (ret)
4999 {
5000 return 1;
5001 }
5002 }
5003
5004 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
5005 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
5006
5007 return 0;
5008 }
5009
5010 static void ventoy_prompt_end(void)
5011 {
5012 int op = 0;
5013 char c;
5014
5015 grub_printf("\n\n\n");
5016 grub_printf(" 1 --- Exit grub\n");
5017 grub_printf(" 2 --- Reboot\n");
5018 grub_printf(" 3 --- Shut down\n");
5019 grub_printf("Please enter your choice: ");
5020 grub_refresh();
5021
5022 while (1)
5023 {
5024 c = grub_getkey();
5025 if (c >= '1' && c <= '3')
5026 {
5027 if (op == 0)
5028 {
5029 op = c - '0';
5030 grub_printf("%c", c);
5031 grub_refresh();
5032 }
5033 }
5034 else if (c == '\r' || c == '\n')
5035 {
5036 if (op)
5037 {
5038 if (op == 1)
5039 {
5040 grub_exit();
5041 }
5042 else if (op == 2)
5043 {
5044 grub_reboot();
5045 }
5046 else if (op == 3)
5047 {
5048 grub_script_execute_sourcecode("halt");
5049 }
5050 }
5051 }
5052 else if (c == '\b')
5053 {
5054 if (op)
5055 {
5056 op = 0;
5057 grub_printf("\rPlease enter your choice: ");
5058 grub_printf("\rPlease enter your choice: ");
5059 grub_refresh();
5060 }
5061 }
5062 }
5063 }
5064
5065 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
5066 {
5067 int ret;
5068
5069 (void)argc;
5070 (void)ctxt;
5071
5072 ret = ventoy_load_part_table(args[0]);
5073 if (ret)
5074 {
5075 ventoy_prompt_end();
5076 }
5077
5078 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
5079 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
5080
5081 return 0;
5082 }
5083
5084 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
5085 {
5086 int ret = 1;
5087 const char *vcfg = NULL;
5088
5089 (void)argc;
5090 (void)ctxt;
5091
5092 vcfg = ventoy_plugin_get_custom_boot(args[0]);
5093 if (vcfg)
5094 {
5095 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
5096 grub_env_set(args[1], vcfg);
5097 ret = 0;
5098 }
5099 else
5100 {
5101 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
5102 }
5103
5104 grub_errno = 0;
5105 return ret;
5106 }
5107
5108
5109 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
5110 {
5111 int id;
5112 grub_uint8_t zeroguid[16] = {0};
5113
5114 (void)argc;
5115 (void)ctxt;
5116
5117 id = (int)grub_strtoul(args[0], NULL, 10);
5118 grub_errno = 0;
5119
5120 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
5121 {
5122 if (id >= 1 && id <= 128)
5123 {
5124 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
5125 {
5126 return 0;
5127 }
5128 }
5129 }
5130 else
5131 {
5132 if (id >= 1 && id <= 4)
5133 {
5134 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
5135 {
5136 return 0;
5137 }
5138 }
5139 }
5140
5141 return 1;
5142 }
5143
5144 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
5145 {
5146 int rc = 1;
5147 char *device_name = NULL;
5148 grub_device_t dev = NULL;
5149 grub_fs_t fs = NULL;
5150 char *label = NULL;
5151
5152 (void)ctxt;
5153
5154 debug("get fs label for %s\n", args[0]);
5155
5156 if (argc != 2)
5157 {
5158 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
5159 return 1;
5160 }
5161
5162 device_name = grub_file_get_device_name(args[0]);
5163 if (!device_name)
5164 {
5165 debug("grub_file_get_device_name failed, %s\n", args[0]);
5166 goto end;
5167 }
5168
5169 dev = grub_device_open(device_name);
5170 if (!dev)
5171 {
5172 debug("grub_device_open failed, %s\n", device_name);
5173 goto end;
5174 }
5175
5176 fs = grub_fs_probe(dev);
5177 if (NULL == fs || NULL == fs->fs_label)
5178 {
5179 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
5180 goto end;
5181 }
5182
5183 fs->fs_label(dev, &label);
5184 if (label)
5185 {
5186 debug("label=<%s>\n", label);
5187 ventoy_set_env(args[1], label);
5188 grub_free(label);
5189 }
5190
5191 rc = 0;
5192
5193 end:
5194
5195 check_free(device_name, grub_free);
5196 check_free(dev, grub_device_close);
5197
5198 return rc;
5199 }
5200
5201 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5202 {
5203 if (!info->dir)
5204 {
5205 grub_snprintf((char *)data, 256, "%s", filename);
5206 return 1;
5207 }
5208
5209 return 0;
5210 }
5211
5212 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5213 {
5214 if (info->dir && filename && filename[0] != '.')
5215 {
5216 grub_snprintf((char *)data, 256, "%s", filename);
5217 return 1;
5218 }
5219
5220 return 0;
5221 }
5222
5223 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
5224 {
5225 int rc = 1;
5226 char *device_name = NULL;
5227 grub_device_t dev = NULL;
5228 grub_fs_t fs = NULL;
5229 char name[256] ={0};
5230
5231 if (argc != 3)
5232 {
5233 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
5234 return 1;
5235 }
5236
5237 device_name = grub_file_get_device_name(args[0]);
5238 if (!device_name)
5239 {
5240 debug("grub_file_get_device_name failed, %s\n", args[0]);
5241 goto end;
5242 }
5243
5244 dev = grub_device_open(device_name);
5245 if (!dev)
5246 {
5247 debug("grub_device_open failed, %s\n", device_name);
5248 goto end;
5249 }
5250
5251 fs = grub_fs_probe(dev);
5252 if (!fs)
5253 {
5254 debug("grub_fs_probe failed, %s\n", device_name);
5255 goto end;
5256 }
5257
5258 fs->fs_dir(dev, args[1], hook, name);
5259 if (name[0])
5260 {
5261 ventoy_set_env(args[2], name);
5262 }
5263
5264 rc = 0;
5265
5266 end:
5267
5268 check_free(device_name, grub_free);
5269 check_free(dev, grub_device_close);
5270
5271 return rc;
5272 }
5273
5274 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
5275 {
5276 (void)ctxt;
5277 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
5278 }
5279
5280 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
5281 {
5282 (void)ctxt;
5283 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
5284 }
5285
5286 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
5287 {
5288 char c;
5289 char *pos = NULL;
5290 char *end = NULL;
5291
5292 (void)ctxt;
5293
5294 if (argc != 2)
5295 {
5296 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
5297 return 1;
5298 }
5299
5300 for (pos = args[0]; *pos; pos++)
5301 {
5302 if (*pos == '.')
5303 {
5304 end = pos;
5305 }
5306 }
5307
5308 if (end)
5309 {
5310 c = *end;
5311 *end = 0;
5312 }
5313
5314 grub_env_set(args[1], args[0]);
5315
5316 if (end)
5317 {
5318 *end = c;
5319 }
5320
5321 return 0;
5322 }
5323
5324 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
5325 {
5326 int i;
5327 int len;
5328 const char *buf;
5329
5330 (void)ctxt;
5331
5332 if (argc != 2)
5333 {
5334 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
5335 return 1;
5336 }
5337
5338 buf = args[0];
5339 len = (int)grub_strlen(buf);
5340 for (i = len; i > 0; i--)
5341 {
5342 if (buf[i - 1] == '/')
5343 {
5344 grub_env_set(args[1], buf + i);
5345 return 0;
5346 }
5347 }
5348
5349 grub_env_set(args[1], buf);
5350
5351 return 0;
5352 }
5353
5354 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5355 {
5356 struct grub_video_mode_info info;
5357 char buf[32];
5358
5359 (void)ctxt;
5360 (void)argc;
5361 (void)args;
5362
5363 if (!g_video_mode_list)
5364 {
5365 ventoy_enum_video_mode();
5366 }
5367
5368 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5369 {
5370 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
5371 }
5372 else
5373 {
5374 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
5375 }
5376
5377 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
5378
5379 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
5380 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
5381
5382 VENTOY_CMD_RETURN(0);
5383 }
5384
5385 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5386 {
5387 struct grub_video_mode_info info;
5388 char buf[32];
5389
5390 (void)ctxt;
5391 (void)argc;
5392 (void)args;
5393
5394 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
5395 {
5396 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
5397 }
5398 else
5399 {
5400 grub_snprintf(buf, sizeof(buf), "0x0x0");
5401 }
5402
5403 grub_env_set(args[0], buf);
5404
5405 VENTOY_CMD_RETURN(0);
5406 }
5407
5408 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
5409 {
5410 int id;
5411 char buf[32];
5412
5413 (void)ctxt;
5414 (void)argc;
5415
5416 if (!g_video_mode_list)
5417 {
5418 return 0;
5419 }
5420
5421 id = (int)grub_strtoul(args[0], NULL, 10);
5422 if (id < g_video_mode_num)
5423 {
5424 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
5425 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
5426 }
5427
5428 grub_env_set(args[1], buf);
5429
5430 VENTOY_CMD_RETURN(0);
5431 }
5432
5433 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
5434 {
5435 grub_uint32_t i;
5436 grub_uint32_t loadsector = 0;
5437 grub_file_t file;
5438 char value[32];
5439 grub_uint32_t boot_catlog = 0;
5440 grub_uint8_t buf[512];
5441
5442 (void)ctxt;
5443
5444 if (argc != 2)
5445 {
5446 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
5447 return 1;
5448 }
5449
5450 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5451 if (!file)
5452 {
5453 debug("failed to open %s\n", args[0]);
5454 return 1;
5455 }
5456
5457 boot_catlog = ventoy_get_iso_boot_catlog(file);
5458 if (boot_catlog == 0)
5459 {
5460 debug("No bootcatlog found\n");
5461 grub_file_close(file);
5462 return 1;
5463 }
5464
5465 grub_memset(buf, 0, sizeof(buf));
5466 grub_file_seek(file, boot_catlog * 2048);
5467 grub_file_read(file, buf, sizeof(buf));
5468 grub_file_close(file);
5469
5470 for (i = 0; i < sizeof(buf); i += 32)
5471 {
5472 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
5473 {
5474 if (buf[i + 32] == 0x88)
5475 {
5476 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
5477 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
5478 break;
5479 }
5480 }
5481 }
5482
5483 if (loadsector == 0)
5484 {
5485 debug("No EFI eltorito info found\n");
5486 return 1;
5487 }
5488
5489 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
5490 grub_env_set(args[1], value);
5491 VENTOY_CMD_RETURN(0);
5492 }
5493
5494 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
5495 {
5496 int curpos;
5497 int printlen;
5498 grub_size_t len;
5499 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
5500
5501 if (pfsdir->initrd[0])
5502 {
5503 return 1;
5504 }
5505
5506 curpos = pfsdir->curpos;
5507 len = grub_strlen(filename);
5508
5509 if (info->dir)
5510 {
5511 if ((len == 1 && filename[0] == '.') ||
5512 (len == 2 && filename[0] == '.' && filename[1] == '.'))
5513 {
5514 return 0;
5515 }
5516
5517 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
5518 pfsdir->dircnt++;
5519
5520 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
5521 pfsdir->curpos = curpos + printlen;
5522 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
5523 pfsdir->curpos = curpos;
5524 pfsdir->fullpath[curpos] = 0;
5525 }
5526 else
5527 {
5528 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
5529 pfsdir->filecnt++;
5530
5531 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
5532 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
5533 {
5534 if (info->size > 32 * VTOY_SIZE_1MB)
5535 {
5536 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
5537 return 1;
5538 }
5539 }
5540 }
5541
5542 return 0;
5543 }
5544
5545 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
5546 {
5547 int i;
5548 char *pos = NULL;
5549 char *device_name = NULL;
5550 grub_device_t dev = NULL;
5551 grub_fs_t fs = NULL;
5552 replace_fs_dir *pfsdir = NULL;
5553
5554 (void)ctxt;
5555
5556 if (argc != 2)
5557 {
5558 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
5559 return 1;
5560 }
5561
5562 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
5563 if (!pfsdir)
5564 {
5565 return 1;
5566 }
5567
5568 device_name = grub_file_get_device_name(args[0]);
5569 if (!device_name)
5570 {
5571 goto fail;
5572 }
5573
5574 dev = grub_device_open(device_name);
5575 if (!dev)
5576 {
5577 goto fail;
5578 }
5579
5580 fs = grub_fs_probe(dev);
5581 if (!fs)
5582 {
5583 goto fail;
5584 }
5585
5586 pfsdir->dev = dev;
5587 pfsdir->fs = fs;
5588 pfsdir->curpos = 1;
5589 pfsdir->fullpath[0] = '/';
5590 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
5591
5592 if (pfsdir->initrd[0])
5593 {
5594 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
5595
5596 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
5597 {
5598 if (pfsdir->initrd[i] == '/')
5599 {
5600 pfsdir->initrd[i] = '\\';
5601 }
5602 }
5603
5604 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
5605 grub_env_set(args[1], pos);
5606 }
5607 else
5608 {
5609 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
5610 }
5611
5612 fail:
5613
5614 grub_check_free(pfsdir);
5615 grub_check_free(device_name);
5616 check_free(dev, grub_device_close);
5617
5618 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5619 }
5620
5621 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5622 {
5623 const char *pager = NULL;
5624
5625 (void)ctxt;
5626 (void)argc;
5627 (void)args;
5628
5629 pager = grub_env_get("pager");
5630 if (NULL == pager)
5631 {
5632 g_pager_flag = 1;
5633 grub_env_set("pager", "1");
5634 }
5635 else if (pager[0] == '1')
5636 {
5637 g_pager_flag = 0;
5638 }
5639 else
5640 {
5641 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
5642 g_pager_flag = 2;
5643 grub_env_set("pager", "1");
5644 }
5645
5646 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5647 }
5648
5649 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
5650 {
5651 (void)ctxt;
5652 (void)argc;
5653 (void)args;
5654
5655 if (g_pager_flag == 1)
5656 {
5657 grub_env_unset("pager");
5658 }
5659 else if (g_pager_flag == 2)
5660 {
5661 grub_env_set("pager", g_old_pager);
5662 }
5663
5664 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5665 }
5666
5667 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
5668 {
5669 if (g_json_case_mis_path[0])
5670 {
5671 return 1;
5672 }
5673
5674 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
5675 {
5676 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
5677 return 1;
5678 }
5679 return 0;
5680 }
5681
5682 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
5683 {
5684 char path[16];
5685 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
5686
5687 if (g_json_case_mis_path[0])
5688 {
5689 return 1;
5690 }
5691
5692 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
5693 {
5694 if (grub_strcasecmp(filename, "ventoy") == 0)
5695 {
5696 grub_snprintf(path, sizeof(path), "/%s", filename);
5697 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
5698 if (g_json_case_mis_path[0])
5699 {
5700 return 1;
5701 }
5702 }
5703 }
5704
5705 return 0;
5706 }
5707
5708 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
5709 {
5710 int fstype = 0;
5711 char *device_name = NULL;
5712 grub_device_t dev = NULL;
5713 grub_fs_t fs = NULL;
5714 chk_case_fs_dir fs_dir;
5715
5716 (void)ctxt;
5717 (void)argc;
5718 (void)args;
5719
5720 device_name = grub_file_get_device_name(args[0]);
5721 if (!device_name)
5722 {
5723 goto out;
5724 }
5725
5726 dev = grub_device_open(device_name);
5727 if (!dev)
5728 {
5729 goto out;
5730 }
5731
5732 fs = grub_fs_probe(dev);
5733 if (!fs)
5734 {
5735 goto out;
5736 }
5737
5738 fstype = ventoy_get_fs_type(fs->name);
5739 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
5740 {
5741 goto out;
5742 }
5743
5744 g_json_case_mis_path[0] = 0;
5745 fs_dir.dev = dev;
5746 fs_dir.fs = fs;
5747 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
5748
5749 if (g_json_case_mis_path[0])
5750 {
5751 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
5752 }
5753
5754 out:
5755
5756 grub_check_free(device_name);
5757 check_free(dev, grub_device_close);
5758
5759 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
5760 }
5761
5762 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
5763 {
5764 grub_disk_t disk;
5765 grub_partition_t part;
5766 char priority_str[3]; /* Maximum value 15 */
5767
5768 (void)ctxt;
5769
5770 if (argc < 2 || argc > 3)
5771 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5772 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
5773
5774 /* Open the disk if it exists */
5775 disk = grub_disk_open (args[0]);
5776 if (!disk)
5777 {
5778 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5779 "Not a disk");
5780 }
5781
5782 part = grub_partition_probe (disk, args[1]);
5783 if (!part)
5784 {
5785 grub_disk_close (disk);
5786 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5787 "No such partition");
5788 }
5789
5790 if (grub_strcmp (part->partmap->name, "gpt"))
5791 {
5792 grub_disk_close (disk);
5793 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5794 "Not a GPT partition");
5795 }
5796
5797 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5798 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5799
5800 if (argc == 3)
5801 {
5802 grub_env_set (args[2], priority_str);
5803 grub_env_export (args[2]);
5804 }
5805 else
5806 {
5807 grub_printf ("Priority is %s\n", priority_str);
5808 }
5809
5810 grub_disk_close (disk);
5811 return GRUB_ERR_NONE;
5812 }
5813
5814
5815 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5816 {
5817 int ret = 1;
5818 int joliet = 0;
5819 grub_file_t file = NULL;
5820 grub_uint32_t loadrba = 0;
5821 grub_uint32_t boot_catlog = 0;
5822 grub_uint8_t sector[512];
5823 boot_info_table *info = NULL;
5824
5825 (void)ctxt;
5826 (void)argc;
5827
5828 /* This also trigger a iso9660 fs parse */
5829 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5830 {
5831 return 0;
5832 }
5833
5834 joliet = grub_iso9660_is_joliet();
5835 if (joliet == 0)
5836 {
5837 return 1;
5838 }
5839
5840 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5841 if (!file)
5842 {
5843 debug("failed to open %s\n", args[0]);
5844 return 1;
5845 }
5846
5847 boot_catlog = ventoy_get_iso_boot_catlog(file);
5848 if (boot_catlog == 0)
5849 {
5850 debug("no bootcatlog found %u\n", boot_catlog);
5851 goto out;
5852 }
5853
5854 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5855 if (loadrba == 0)
5856 {
5857 debug("no bios eltorito rba found %u\n", loadrba);
5858 goto out;
5859 }
5860
5861 grub_file_seek(file, loadrba * 2048);
5862 grub_file_read(file, sector, 512);
5863
5864 info = (boot_info_table *)sector;
5865 if (info->bi_data0 == 0x7c6ceafa &&
5866 info->bi_data1 == 0x90900000 &&
5867 info->bi_PrimaryVolumeDescriptor == 16 &&
5868 info->bi_BootFileLocation == loadrba)
5869 {
5870 debug("bootloader is syslinux, %u.\n", loadrba);
5871 ret = 0;
5872 }
5873
5874 out:
5875
5876 grub_file_close(file);
5877 grub_errno = GRUB_ERR_NONE;
5878 return ret;
5879 }
5880
5881 static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args)
5882 {
5883 int n = 0;
5884 ventoy_vlnk_part *node;
5885
5886 (void)ctxt;
5887 (void)argc;
5888 (void)args;
5889
5890 for (node = g_vlnk_part_list; node; node = node->next)
5891 {
5892 grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n",
5893 ++n, node->device, node->disksig,
5894 (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A"));
5895 }
5896
5897 return 0;
5898 }
5899
5900 static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args)
5901 {
5902 int len = 0;
5903
5904 (void)ctxt;
5905
5906 if (argc == 1)
5907 {
5908 len = (int)grub_strlen(args[0]);
5909 if (grub_file_is_vlnk_suffix(args[0], len))
5910 {
5911 return 0;
5912 }
5913 }
5914
5915 return 1;
5916 }
5917
5918 static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args)
5919 {
5920 int vlnk = 0;
5921 const char *name = NULL;
5922
5923 (void)ctxt;
5924
5925 if (argc == 2)
5926 {
5927 grub_env_unset(args[1]);
5928 name = grub_file_get_vlnk(args[0], &vlnk);
5929 if (vlnk)
5930 {
5931 debug("VLNK SRC: <%s>\n", args[0]);
5932 debug("VLNK DST: <%s>\n", name);
5933 grub_env_set(args[1], name);
5934 return 0;
5935 }
5936 }
5937
5938 return 1;
5939 }
5940
5941 static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
5942 {
5943 int ret = 1;
5944 int len = 0;
5945 grub_file_t file = NULL;
5946 ventoy_vlnk vlnk;
5947 char dst[512];
5948
5949 (void)ctxt;
5950
5951 if (argc != 1)
5952 {
5953 goto out;
5954 }
5955
5956 len = (int)grub_strlen(args[0]);
5957 if (!grub_file_is_vlnk_suffix(args[0], len))
5958 {
5959 grub_printf("Invalid vlnk suffix\n");
5960 goto out;
5961 }
5962
5963 file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK);
5964 if (!file)
5965 {
5966 grub_printf("Failed to open %s\n", args[0]);
5967 goto out;
5968 }
5969
5970 if (file->size != 32768)
5971 {
5972 grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size);
5973 goto out;
5974 }
5975
5976 grub_memset(&vlnk, 0, sizeof(vlnk));
5977 grub_file_read(file, &vlnk, sizeof(vlnk));
5978
5979 ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst));
5980
5981 out:
5982
5983 grub_refresh();
5984 check_free(file, grub_file_close);
5985 grub_errno = GRUB_ERR_NONE;
5986 return ret;
5987 }
5988
5989 static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args)
5990 {
5991 (void)ctxt;
5992 (void)argc;
5993 (void)args;
5994
5995 g_iso_vd_id_publisher[0] = 0;
5996 g_iso_vd_id_prepare[0] = 0;
5997 g_iso_vd_id_application[0] = 0;
5998
5999 return 0;
6000 }
6001
6002 static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args)
6003 {
6004 int ret = 1;
6005 int offset = 318;
6006 grub_file_t file = NULL;
6007
6008 (void)ctxt;
6009 (void)argc;
6010
6011 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
6012 if (!file)
6013 {
6014 grub_printf("Failed to open %s\n", args[0]);
6015 goto out;
6016 }
6017
6018 grub_file_seek(file, 16 * 2048 + offset);
6019 grub_file_read(file, g_iso_vd_id_publisher, 128);
6020
6021 offset += 128;
6022 grub_file_seek(file, 16 * 2048 + offset);
6023 grub_file_read(file, g_iso_vd_id_prepare, 128);
6024
6025 offset += 128;
6026 grub_file_seek(file, 16 * 2048 + offset);
6027 grub_file_read(file, g_iso_vd_id_application, 128);
6028
6029 out:
6030
6031 check_free(file, grub_file_close);
6032 grub_errno = GRUB_ERR_NONE;
6033 return ret;
6034 }
6035
6036 static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args)
6037 {
6038 int ret = 1;
6039 char *id = g_iso_vd_id_publisher;
6040
6041 (void)ctxt;
6042 (void)argc;
6043
6044 if (args[0][0] == '1')
6045 {
6046 id = g_iso_vd_id_prepare;
6047 }
6048 else if (args[0][0] == '2')
6049 {
6050 id = g_iso_vd_id_application;
6051 }
6052
6053 if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0)
6054 {
6055 ret = 0;
6056 }
6057
6058 if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0)
6059 {
6060 ret = 0;
6061 }
6062
6063 grub_errno = GRUB_ERR_NONE;
6064 return ret;
6065 }
6066
6067 static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args)
6068 {
6069 (void)ctxt;
6070 (void)argc;
6071
6072 g_ventoy_fn_mutex = 0;
6073 if (argc == 1 && args[0][0] == '1' && args[0][1] == 0)
6074 {
6075 g_ventoy_fn_mutex = 1;
6076 }
6077
6078 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6079 }
6080
6081 static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args)
6082 {
6083 grub_uint64_t total;
6084 grub_uint64_t org_required;
6085 grub_uint64_t new_required;
6086
6087 (void)ctxt;
6088 (void)argc;
6089 (void)args;
6090
6091 #ifdef GRUB_MACHINE_EFI
6092 grub_efi_get_reserved_page_num(&total, &org_required, &new_required);
6093 grub_printf("Total pages: %llu\n", (unsigned long long)total);
6094 grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required);
6095 grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required);
6096 #else
6097 (void)total;
6098 (void)org_required;
6099 (void)new_required;
6100 grub_printf("Non EFI mode!\n");
6101 #endif
6102
6103 grub_refresh();
6104
6105 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6106 }
6107
6108 static grub_err_t ventoy_cmd_need_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
6109 {
6110 const char *env = NULL;
6111
6112 (void)ctxt;
6113 (void)argc;
6114
6115 if (g_ventoy_memdisk_mode || g_ventoy_grub2_mode || g_ventoy_wimboot_mode || g_ventoy_iso_raw)
6116 {
6117 return 1;
6118 }
6119
6120 if (ventoy_check_mode_by_name(args[0], "vtgrub2") ||
6121 ventoy_check_mode_by_name(args[0], "vtwimboot") ||
6122 ventoy_check_mode_by_name(args[0], "vtmemdisk") ||
6123 ventoy_check_mode_by_name(args[0], "vtnormal")
6124 )
6125 {
6126 return 1;
6127 }
6128
6129 env = grub_env_get("VTOY_SECONDARY_BOOT_MENU");
6130 if (env && env[0] == '0' && env[1] == 0)
6131 {
6132 return 1;
6133 }
6134
6135 return 0;
6136 }
6137
6138 static grub_err_t ventoy_cmd_show_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args)
6139 {
6140 int n = 0;
6141 int pos = 0;
6142 int len = 0;
6143 int select = 0;
6144 int timeout = 0;
6145 char *cmd = NULL;
6146 const char *env = NULL;
6147 ulonglong fsize = 0;
6148 char cfgfile[128];
6149 int seldata[16] = {0};
6150
6151 (void)ctxt;
6152 (void)argc;
6153
6154 len = 8 * VTOY_SIZE_1KB;
6155 cmd = (char *)grub_malloc(len);
6156 if (!cmd)
6157 {
6158 return 1;
6159 }
6160
6161 g_vtoy_secondary_need_recover = 0;
6162 grub_env_unset("VTOY_CHKSUM_FILE_PATH");
6163
6164 env = grub_env_get("VTOY_SECONDARY_TIMEOUT");
6165 if (env)
6166 {
6167 timeout = (int)grub_strtol(env, NULL, 10);
6168 }
6169
6170 if (timeout > 0)
6171 {
6172 vtoy_len_ssprintf(cmd, pos, len, "set timeout=%d\n", timeout);
6173 }
6174
6175 fsize = grub_strtoull(args[2], NULL, 10);
6176
6177 vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_NORMAL_MODE", "second_normal"); seldata[n++] = 1;
6178
6179 if (grub_strcmp(args[1], "Unix") != 0)
6180 {
6181 if (grub_strcmp(args[1], "Windows") == 0)
6182 {
6183 vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_WIMBOOT_MODE", "second_wimboot"); seldata[n++] = 2;
6184 }
6185 else
6186 {
6187 vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_GRUB2_MODE", "second_grub2"); seldata[n++] = 3;
6188 }
6189
6190 if (fsize <= VTOY_SIZE_1GB)
6191 {
6192 vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_MEMDISK_MODE", "second_memdisk"); seldata[n++] = 4;
6193 }
6194 }
6195
6196 vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_FILE_CHKSUM", "second_checksum"); seldata[n++] = 5;
6197
6198 do {
6199 g_ventoy_menu_esc = 1;
6200 g_ventoy_suppress_esc = 1;
6201 g_ventoy_suppress_esc_default = 0;
6202 g_ventoy_secondary_menu_on = 1;
6203 grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos);
6204 grub_script_execute_sourcecode(cfgfile);
6205 g_ventoy_menu_esc = 0;
6206 g_ventoy_suppress_esc = 0;
6207 g_ventoy_suppress_esc_default = 1;
6208 g_ventoy_secondary_menu_on = 0;
6209
6210 select = seldata[g_ventoy_last_entry];
6211
6212 if (select == 2)
6213 {
6214 g_ventoy_wimboot_mode = 1;
6215 g_vtoy_secondary_need_recover = 1;
6216 }
6217 else if (select == 3)
6218 {
6219 g_ventoy_grub2_mode = 1;
6220 g_vtoy_secondary_need_recover = 2;
6221 }
6222 else if (select == 4)
6223 {
6224 g_ventoy_memdisk_mode = 1;
6225 g_vtoy_secondary_need_recover = 3;
6226 }
6227 else if (select == 5)
6228 {
6229 grub_env_set("VTOY_CHKSUM_FILE_PATH", args[0]);
6230 grub_script_execute_sourcecode("configfile $vtoy_efi_part/grub/checksum.cfg");
6231 }
6232 }while (select == 5);
6233
6234 grub_free(cmd);
6235 return 0;
6236 }
6237
6238 static grub_err_t ventoy_cmd_secondary_recover_mode(grub_extcmd_context_t ctxt, int argc, char **args)
6239 {
6240 (void)ctxt;
6241 (void)argc;
6242 (void)args;
6243
6244 if (g_vtoy_secondary_need_recover == 1)
6245 {
6246 g_ventoy_wimboot_mode = 0;
6247 }
6248 else if (g_vtoy_secondary_need_recover == 2)
6249 {
6250 g_ventoy_grub2_mode = 0;
6251 }
6252 else if (g_vtoy_secondary_need_recover == 3)
6253 {
6254 g_ventoy_memdisk_mode = 0;
6255 }
6256
6257 g_vtoy_secondary_need_recover = 0;
6258
6259 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6260 }
6261
6262 static grub_err_t ventoy_cmd_fs_ignore_case(grub_extcmd_context_t ctxt, int argc, char **args)
6263 {
6264 (void)ctxt;
6265 (void)argc;
6266
6267 if (args[0][0] == '0')
6268 {
6269 g_ventoy_case_insensitive = 0;
6270 }
6271 else
6272 {
6273 g_ventoy_case_insensitive = 1;
6274 }
6275
6276 return 0;
6277 }
6278
6279 static grub_err_t ventoy_cmd_init_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args)
6280 {
6281 (void)ctxt;
6282 (void)argc;
6283
6284 ventoy_plugin_load_menu_lang(1, args[0]);
6285 VENTOY_CMD_RETURN(0);
6286 }
6287
6288 static grub_err_t ventoy_cmd_load_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args)
6289 {
6290 (void)ctxt;
6291 (void)argc;
6292
6293 ventoy_plugin_load_menu_lang(0, args[0]);
6294 VENTOY_CMD_RETURN(0);
6295 }
6296
6297 static grub_err_t ventoy_cmd_vtoychksum_exist(grub_extcmd_context_t ctxt, int argc, char **args)
6298 {
6299 int cnt;
6300 char c;
6301 char *pos = NULL;
6302
6303 (void)ctxt;
6304 (void)argc;
6305
6306 cnt = ventoy_str_chrcnt(args[1], '/');
6307 if (cnt > 1)
6308 {
6309 pos = grub_strrchr(args[1], '/');
6310 c = *pos;
6311 *pos = 0;
6312 if (ventoy_check_file_exist("%s%s/VENTOY_CHECKSUM", args[0], args[1]))
6313 {
6314 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6315 }
6316 *pos = c;
6317 }
6318
6319 if (ventoy_check_file_exist("%s/VENTOY_CHECKSUM", args[0]))
6320 {
6321 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
6322 }
6323
6324 return 1;
6325 }
6326
6327 static int ventoy_chksum_pathcmp(int chktype, char *rlpath, char *rdpath)
6328 {
6329 char *pos1 = NULL;
6330 char *pos2 = NULL;
6331
6332 if (chktype == 2)
6333 {
6334 pos1 = ventoy_str_basename(rlpath);
6335 pos2 = ventoy_str_basename(rdpath);
6336 return grub_strcmp(pos1, pos2);
6337 }
6338 else if (chktype == 3 || chktype == 4)
6339 {
6340 if (grub_strcmp(rlpath, rdpath) == 0 || grub_strcmp(rlpath + 1, rdpath) == 0)
6341 {
6342 return 0;
6343 }
6344 }
6345
6346 return 1;
6347 }
6348
6349 static int ventoy_find_checksum
6350 (
6351 grub_file_t file,
6352 const char *uname,
6353 int retlen,
6354 char *path,
6355 int chktype,
6356 char *chksum
6357 )
6358 {
6359 int ulen;
6360 char *pos = NULL;
6361 char *pos1 = NULL;
6362 char *pos2 = NULL;
6363 char *buf = NULL;
6364 char *currline = NULL;
6365 char *nextline = NULL;
6366
6367 ulen = (int)grub_strlen(uname);
6368
6369 /* read file to buffer */
6370 buf = grub_malloc(file->size + 4);
6371 if (!buf)
6372 {
6373 return 1;
6374 }
6375 grub_file_read(file, buf, file->size);
6376 buf[file->size] = 0;
6377
6378 /* parse each line */
6379 for (currline = buf; currline; currline = nextline)
6380 {
6381 nextline = ventoy_get_line(currline);
6382 VTOY_SKIP_SPACE(currline);
6383
6384 if (grub_strncasecmp(currline, uname, ulen) == 0)
6385 {
6386 pos = grub_strchr(currline, '=');
6387 pos1 = grub_strchr(currline, '(');
6388 pos2 = grub_strchr(currline, ')');
6389
6390 if (pos && pos1 && pos2)
6391 {
6392 *pos2 = 0;
6393 if (ventoy_chksum_pathcmp(chktype, path, pos1 + 1) == 0)
6394 {
6395 VTOY_SKIP_SPACE_NEXT(pos, 1);
6396 grub_memcpy(chksum, pos, retlen);
6397 goto end;
6398 }
6399 }
6400 }
6401 else if (ventoy_str_len_alnum(currline, retlen))
6402 {
6403 VTOY_SKIP_SPACE_NEXT_EX(pos, currline, retlen);
6404 if (ventoy_chksum_pathcmp(chktype, path, pos) == 0)
6405 {
6406 grub_memcpy(chksum, currline, retlen);
6407 goto end;
6408 }
6409 }
6410 }
6411
6412 end:
6413 grub_free(buf);
6414 return 0;
6415 }
6416
6417 static int ventoy_check_chkfile(const char *isopart, char *path, const char *lchkname, grub_file_t *pfile)
6418 {
6419 int ret = 0;
6420 int cnt = 0;
6421 char c = 0;
6422 char *pos = NULL;
6423 grub_file_t file = NULL;
6424
6425 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s.%s", isopart, path, lchkname);
6426 if (file)
6427 {
6428 VTOY_GOTO_END(1);
6429 }
6430
6431 cnt = ventoy_str_chrcnt(path, '/');
6432 if (cnt > 1)
6433 {
6434 pos = grub_strrchr(path, '/');
6435 c = *pos;
6436 *pos = 0;
6437
6438 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s/VENTOY_CHECKSUM", isopart, path);
6439 if (file)
6440 {
6441 *pos = c;
6442 VTOY_GOTO_END(2);
6443 }
6444 *pos = c;
6445 }
6446
6447 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/VENTOY_CHECKSUM", isopart);
6448 if (file)
6449 {
6450 ret = (cnt > 1) ? 3 : 4;
6451 }
6452
6453 end:
6454
6455 if (pfile)
6456 {
6457 *pfile = file;
6458 }
6459 else
6460 {
6461 check_free(file, grub_file_close);
6462 }
6463 return ret;
6464 }
6465
6466 static grub_err_t ventoy_cmd_cmp_checksum(grub_extcmd_context_t ctxt, int argc, char **args)
6467 {
6468 int index = 0;
6469 int chktype = 0;
6470 char *pos = NULL;
6471 grub_file_t file = NULL;
6472 const char *calc_value = NULL;
6473 const char *isopart = NULL;
6474 char fchksum[64];
6475 char readchk[256] = {0};
6476 char filebuf[512] = {0};
6477 int retlen[] = { 32, 40, 64, 128 };
6478 char uchkname[16];
6479
6480 (void)ctxt;
6481
6482 index = (int)grub_strtol(args[0], NULL, 10);
6483 if (argc != 2 || index < 0 || index >= (int)ARRAY_SIZE(retlen))
6484 {
6485 return 1;
6486 }
6487
6488 grub_strncpy(uchkname, g_lower_chksum_name[index], sizeof(uchkname));
6489 ventoy_str_toupper(uchkname);
6490
6491 isopart = grub_env_get("vtoy_iso_part");
6492 calc_value = grub_env_get("VT_LAST_CHECK_SUM");
6493
6494 chktype = ventoy_check_chkfile(isopart, args[1], g_lower_chksum_name[index], &file);
6495 if (chktype <= 0)
6496 {
6497 grub_printf("\n\nNo checksum file found.\n");
6498 goto end;
6499 }
6500
6501 if (chktype == 1)
6502 {
6503 grub_snprintf(fchksum, sizeof(fchksum), ".%s", g_lower_chksum_name[index]);
6504 grub_memset(filebuf, 0, sizeof(filebuf));
6505 grub_file_read(file, filebuf, 511);
6506
6507 pos = grub_strchr(filebuf, '=');
6508 if (pos)
6509 {
6510 VTOY_SKIP_SPACE_NEXT(pos, 1);
6511 grub_memcpy(readchk, pos, retlen[index]);
6512 }
6513 else
6514 {
6515 grub_memcpy(readchk, filebuf, retlen[index]);
6516 }
6517 }
6518 else if (chktype == 3 || chktype == 4)
6519 {
6520 grub_snprintf(fchksum, sizeof(fchksum), "global VENTOY_CHECKSUM");
6521 ventoy_find_checksum(file, uchkname, retlen[index], args[1], chktype, readchk);
6522 if (readchk[0] == 0)
6523 {
6524 grub_printf("\n\n%s value not found in %s.\n", uchkname, fchksum);
6525 goto end;
6526 }
6527 }
6528 else
6529 {
6530 grub_snprintf(fchksum, sizeof(fchksum), "local VENTOY_CHECKSUM");
6531 ventoy_find_checksum(file, uchkname, retlen[index], args[1], chktype, readchk);
6532 if (readchk[0] == 0)
6533 {
6534 grub_file_close(file);
6535 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/VENTOY_CHECKSUM", isopart);
6536 if (file)
6537 {
6538 grub_snprintf(fchksum, sizeof(fchksum), "global VENTOY_CHECKSUM");
6539 ventoy_find_checksum(file, uchkname, retlen[index], args[1], 3, readchk);
6540 if (readchk[0] == 0)
6541 {
6542 grub_printf("\n\n%s value not found in both local and global VENTOY_CHECKSUM.\n", uchkname);
6543 goto end;
6544 }
6545 }
6546 }
6547 }
6548
6549 if (grub_strcasecmp(calc_value, readchk) == 0)
6550 {
6551 grub_printf("\n\nCheck %s value with %s file. [ SUCCESS ]\n", uchkname, fchksum);
6552 }
6553 else
6554 {
6555 grub_printf("\n\nCheck %s value with %s file. [ ERROR ]\n", uchkname, fchksum);
6556 grub_printf("The %s value in %s file is:\n%s\n", uchkname, fchksum, readchk);
6557 }
6558
6559 end:
6560 grub_refresh();
6561 check_free(file, grub_file_close);
6562 VENTOY_CMD_RETURN(0);
6563 }
6564
6565
6566 static const char * ventoy_menu_lang_read_hook(struct grub_env_var *var, const char *val)
6567 {
6568 (void)var;
6569 return ventoy_get_vmenu_title(val);
6570 }
6571
6572 int ventoy_env_init(void)
6573 {
6574 int i;
6575 char buf[64];
6576
6577 grub_env_set("vtdebug_flag", "");
6578
6579 grub_register_vtoy_menu_lang_hook(ventoy_menu_lang_read_hook);
6580 ventoy_ctrl_var_init();
6581 ventoy_global_var_init();
6582
6583 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
6584 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6585 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
6586 for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++)
6587 {
6588 g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size);
6589 }
6590
6591 ventoy_filt_register(0, ventoy_wrapper_open);
6592
6593 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
6594 if (g_grub_param)
6595 {
6596 g_grub_param->grub_env_get = grub_env_get;
6597 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
6598 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
6599 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
6600 grub_env_set("env_param", buf);
6601 grub_env_set("ventoy_env_param", buf);
6602
6603 grub_env_export("env_param");
6604 grub_env_export("ventoy_env_param");
6605 }
6606
6607 grub_env_export("vtoy_winpeshl_ini_addr");
6608 grub_env_export("vtoy_winpeshl_ini_size");
6609
6610 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
6611 grub_env_set("vtoy_chain_file_size", buf);
6612 grub_env_export("vtoy_chain_file_size");
6613
6614 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
6615 grub_env_set("vtoy_chain_file_read", buf);
6616 grub_env_export("vtoy_chain_file_read");
6617
6618 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_get_vmenu_title);
6619 grub_env_set("VTOY_VMENU_FUNC_ADDR", buf);
6620 grub_env_export("VTOY_VMENU_FUNC_ADDR");
6621
6622 grub_snprintf(buf, sizeof(buf), "%s-%s", GRUB_TARGET_CPU, GRUB_PLATFORM);
6623 grub_env_set("grub_cpu_platform", buf);
6624 grub_env_export("grub_cpu_platform");
6625
6626 return 0;
6627 }
6628
6629
6630
6631 static cmd_para ventoy_cmds[] =
6632 {
6633 { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL },
6634 { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL },
6635 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
6636 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
6637 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
6638 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
6639 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
6640 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6641 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
6642 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
6643 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
6644 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
6645 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
6646 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
6647 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
6648 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
6649 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
6650 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
6651 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
6652 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
6653 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
6654 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
6655 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
6656 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
6657 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
6658 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
6659 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
6660
6661 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
6662 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
6663 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
6664 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
6665 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
6666 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
6667 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
6668
6669 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
6670 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
6671 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
6672 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
6673 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
6674 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
6675 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
6676 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
6677 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
6678 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
6679
6680
6681 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
6682 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
6683 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
6684 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
6685 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
6686 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
6687 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
6688 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
6689 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
6690 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
6691 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
6692
6693 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
6694 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
6695 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
6696 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
6697 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
6698 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
6699 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
6700
6701 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6702 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
6703 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
6704 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
6705 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
6706 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
6707 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
6708 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
6709 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
6710 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
6711
6712 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
6713 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
6714 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
6715 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
6716 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
6717 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
6718 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
6719 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
6720 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
6721
6722 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
6723 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
6724 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
6725 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
6726
6727
6728 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
6729 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
6730 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
6731
6732 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
6733 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
6734 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
6735
6736
6737 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
6738 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
6739 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
6740 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
6741 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
6742 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
6743 { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL },
6744 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
6745 { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL },
6746 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
6747 { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL },
6748 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
6749 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
6750 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
6751
6752 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
6753 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
6754 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
6755 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
6756 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
6757 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
6758 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
6759 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
6760 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
6761 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
6762 { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL },
6763 { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL },
6764
6765 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
6766 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
6767 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
6768 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
6769 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
6770 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
6771 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
6772 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
6773 { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL },
6774 { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL },
6775 { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL },
6776 { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL },
6777 { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL },
6778 { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL },
6779 { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL },
6780 { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL },
6781 { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL },
6782 { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL },
6783 { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL },
6784 { "vt_is_standard_winiso", ventoy_cmd_is_standard_winiso, 0, NULL, "", "", NULL },
6785 { "vt_sel_winpe_wim", ventoy_cmd_sel_winpe_wim, 0, NULL, "", "", NULL },
6786 { "vt_need_secondary_menu", ventoy_cmd_need_secondary_menu, 0, NULL, "", "", NULL },
6787 { "vt_show_secondary_menu", ventoy_cmd_show_secondary_menu, 0, NULL, "", "", NULL },
6788 { "vt_fs_ignore_case", ventoy_cmd_fs_ignore_case, 0, NULL, "", "", NULL },
6789 { "vt_systemd_menu", ventoy_cmd_linux_systemd_menu, 0, NULL, "", "", NULL },
6790 { "vt_limine_menu", ventoy_cmd_linux_limine_menu, 0, NULL, "", "", NULL },
6791 { "vt_secondary_recover_mode", ventoy_cmd_secondary_recover_mode, 0, NULL, "", "", NULL },
6792 { "vt_load_menu_lang", ventoy_cmd_load_menu_lang, 0, NULL, "", "", NULL },
6793 { "vt_init_menu_lang", ventoy_cmd_init_menu_lang, 0, NULL, "", "", NULL },
6794 { "vt_cur_menu_lang", ventoy_cmd_cur_menu_lang, 0, NULL, "", "", NULL },
6795 { "vt_vtoychksum_exist", ventoy_cmd_vtoychksum_exist, 0, NULL, "", "", NULL },
6796 { "vt_cmp_checksum", ventoy_cmd_cmp_checksum, 0, NULL, "", "", NULL },
6797
6798 };
6799
6800 int ventoy_register_all_cmd(void)
6801 {
6802 grub_uint32_t i;
6803 cmd_para *cur = NULL;
6804
6805 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6806 {
6807 cur = ventoy_cmds + i;
6808 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
6809 cur->summary, cur->description, cur->parser);
6810 }
6811
6812 return 0;
6813 }
6814
6815 int ventoy_unregister_all_cmd(void)
6816 {
6817 grub_uint32_t i;
6818
6819 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
6820 {
6821 grub_unregister_extcmd(ventoy_cmds[i].cmd);
6822 }
6823
6824 return 0;
6825 }
6826
6827