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