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