]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
1.0.14 release
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy.c
1 /******************************************************************************
2 * ventoy.c
3 *
4 * Copyright (c) 2020, 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 #ifdef GRUB_MACHINE_EFI
38 #include <grub/efi/efi.h>
39 #endif
40 #include <grub/time.h>
41 #include <grub/relocator.h>
42 #include <grub/ventoy.h>
43 #include "ventoy_def.h"
44
45 GRUB_MOD_LICENSE ("GPLv3+");
46
47 int g_ventoy_debug = 0;
48 static int g_efi_os = 0xFF;
49 initrd_info *g_initrd_img_list = NULL;
50 initrd_info *g_initrd_img_tail = NULL;
51 int g_initrd_img_count = 0;
52 int g_valid_initrd_count = 0;
53 int g_default_menu_mode = 0;
54 int g_filt_dot_underscore_file = 0;
55 static grub_file_t g_old_file;
56
57 char g_iso_path[256];
58 char g_img_swap_tmp_buf[1024];
59 img_info g_img_swap_tmp;
60 img_info *g_ventoy_img_list = NULL;
61
62 int g_ventoy_img_count = 0;
63
64 grub_device_t g_enum_dev = NULL;
65 grub_fs_t g_enum_fs = NULL;
66 img_iterator_node g_img_iterator_head;
67 img_iterator_node *g_img_iterator_tail = NULL;
68
69 grub_uint8_t g_ventoy_break_level = 0;
70 grub_uint8_t g_ventoy_debug_level = 0;
71 grub_uint8_t g_ventoy_chain_type = 0;
72
73 grub_uint8_t *g_ventoy_cpio_buf = NULL;
74 grub_uint32_t g_ventoy_cpio_size = 0;
75 cpio_newc_header *g_ventoy_initrd_head = NULL;
76 grub_uint8_t *g_ventoy_runtime_buf = NULL;
77
78 ventoy_grub_param *g_grub_param = NULL;
79
80 ventoy_guid g_ventoy_guid = VENTOY_GUID;
81
82 ventoy_img_chunk_list g_img_chunk_list;
83
84 int g_wimboot_enable = 0;
85 ventoy_img_chunk_list g_wimiso_chunk_list;
86 char *g_wimiso_path = NULL;
87
88 static char *g_tree_script_buf = NULL;
89 static int g_tree_script_pos = 0;
90
91 static char *g_list_script_buf = NULL;
92 static int g_list_script_pos = 0;
93
94 static const char *g_menu_class[] =
95 {
96 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg"
97 };
98
99 static const char *g_menu_prefix[] =
100 {
101 "iso", "wim", "efi", "img"
102 };
103
104 void ventoy_debug(const char *fmt, ...)
105 {
106 va_list args;
107
108 va_start (args, fmt);
109 grub_vprintf (fmt, args);
110 va_end (args);
111 }
112
113 int ventoy_is_efi_os(void)
114 {
115 if (g_efi_os > 1)
116 {
117 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
118 }
119
120 return g_efi_os;
121 }
122
123 static int ventoy_get_fs_type(const char *fs)
124 {
125 if (NULL == fs)
126 {
127 return ventoy_fs_max;
128 }
129 else if (grub_strncmp(fs, "exfat", 5) == 0)
130 {
131 return ventoy_fs_exfat;
132 }
133 else if (grub_strncmp(fs, "ntfs", 4) == 0)
134 {
135 return ventoy_fs_ntfs;
136 }
137 else if (grub_strncmp(fs, "ext", 3) == 0)
138 {
139 return ventoy_fs_ext;
140 }
141 else if (grub_strncmp(fs, "xfs", 3) == 0)
142 {
143 return ventoy_fs_xfs;
144 }
145 else if (grub_strncmp(fs, "udf", 3) == 0)
146 {
147 return ventoy_fs_udf;
148 }
149 else if (grub_strncmp(fs, "fat", 3) == 0)
150 {
151 return ventoy_fs_fat;
152 }
153
154 return ventoy_fs_max;
155 }
156
157 static int ventoy_string_check(const char *str, grub_char_check_func check)
158 {
159 if (!str)
160 {
161 return 0;
162 }
163
164 for ( ; *str; str++)
165 {
166 if (!check(*str))
167 {
168 return 0;
169 }
170 }
171
172 return 1;
173 }
174
175
176 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
177 {
178 grub_memcpy(buf, (char *)file->data + file->offset, len);
179 return len;
180 }
181
182 static grub_err_t ventoy_fs_close(grub_file_t file)
183 {
184 grub_file_close(g_old_file);
185 grub_free(file->data);
186
187 file->device = 0;
188 file->name = 0;
189
190 return 0;
191 }
192
193 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
194 {
195 int len;
196 grub_file_t file;
197 static struct grub_fs vtoy_fs =
198 {
199 .name = "vtoy",
200 .fs_dir = 0,
201 .fs_open = 0,
202 .fs_read = ventoy_fs_read,
203 .fs_close = ventoy_fs_close,
204 .fs_label = 0,
205 .next = 0
206 };
207
208 if (type != 52)
209 {
210 return rawFile;
211 }
212
213 file = (grub_file_t)grub_zalloc(sizeof (*file));
214 if (!file)
215 {
216 return 0;
217 }
218
219 file->data = grub_malloc(rawFile->size + 4096);
220 if (!file->data)
221 {
222 return 0;
223 }
224
225 grub_file_read(rawFile, file->data, rawFile->size);
226 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
227
228 g_old_file = rawFile;
229
230 file->size = rawFile->size + len;
231 file->device = rawFile->device;
232 file->fs = &vtoy_fs;
233 file->not_easily_seekable = 1;
234
235 return file;
236 }
237
238 static int ventoy_check_decimal_var(const char *name, long *value)
239 {
240 const char *value_str = NULL;
241
242 value_str = grub_env_get(name);
243 if (NULL == value_str)
244 {
245 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
246 }
247
248 if (!ventoy_is_decimal(value_str))
249 {
250 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
251 }
252
253 *value = grub_strtol(value_str, NULL, 10);
254
255 return GRUB_ERR_NONE;
256 }
257
258 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
259 {
260 if (argc != 1)
261 {
262 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
263 }
264
265 if (0 == grub_strcmp(args[0], "on"))
266 {
267 g_ventoy_debug = 1;
268 grub_env_set("vtdebug_flag", "debug");
269 }
270 else
271 {
272 g_ventoy_debug = 0;
273 grub_env_set("vtdebug_flag", "");
274 }
275
276 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
277 }
278
279 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
280 {
281 (void)ctxt;
282
283 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
284 {
285 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
286 grub_printf(" level:\r\n");
287 grub_printf(" 01/11: busybox / (+cat log)\r\n");
288 grub_printf(" 02/12: initrd / (+cat log)\r\n");
289 grub_printf(" 03/13: hook / (+cat log)\r\n");
290 grub_printf("\r\n");
291 grub_printf(" debug:\r\n");
292 grub_printf(" 0: debug is on\r\n");
293 grub_printf(" 1: debug is off\r\n");
294 grub_printf("\r\n");
295 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
296 }
297
298 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
299
300 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
301 {
302 g_ventoy_debug_level = 1;
303 }
304
305 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
306 }
307
308 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
309 {
310 long value_long = 0;
311 char buf[32];
312
313 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
314 {
315 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
316 }
317
318 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
319 {
320 return grub_errno;
321 }
322
323 value_long += grub_strtol(args[1], NULL, 10);
324
325 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
326 grub_env_set(args[0], buf);
327
328 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
329 }
330
331 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
332 {
333 int rc = 1;
334 char buf[32];
335 grub_file_t file;
336
337 (void)ctxt;
338 (void)argc;
339 (void)args;
340
341 if (argc != 2)
342 {
343 return rc;
344 }
345
346 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
347 if (file == NULL)
348 {
349 debug("failed to open file <%s> for udf check\n", args[0]);
350 return 1;
351 }
352
353 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
354
355 grub_env_set(args[1], buf);
356
357 grub_file_close(file);
358 rc = 0;
359
360 return rc;
361 }
362
363 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
364 {
365 grub_file_t file;
366
367 (void)ctxt;
368 (void)argc;
369 (void)args;
370
371 g_wimboot_enable = 0;
372 grub_check_free(g_wimiso_path);
373 grub_check_free(g_wimiso_chunk_list.chunk);
374
375 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
376 if (!file)
377 {
378 return 0;
379 }
380
381 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
382 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
383 if (NULL == g_wimiso_chunk_list.chunk)
384 {
385 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
386 }
387
388 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
389 g_wimiso_chunk_list.cur_chunk = 0;
390
391 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
392
393 g_wimboot_enable = 1;
394 g_wimiso_path = grub_strdup(args[0]);
395
396 grub_file_close(file);
397
398 return 0;
399 }
400
401 static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
402 {
403 int rc = 1;
404 char name[32];
405 char value[32];
406 char *buf = NULL;
407 grub_file_t file;
408
409 (void)ctxt;
410 (void)argc;
411 (void)args;
412
413 if (argc != 2)
414 {
415 return rc;
416 }
417
418 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
419 if (file == NULL)
420 {
421 debug("failed to open file <%s> for udf check\n", args[0]);
422 return 1;
423 }
424
425 #ifdef GRUB_MACHINE_EFI
426 buf = (char *)grub_efi_allocate_iso_buf(file->size);
427 #else
428 buf = (char *)grub_malloc(file->size);
429 #endif
430
431 grub_file_read(file, buf, file->size);
432
433 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
434 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
435 grub_env_set(name, value);
436
437 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
438 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
439 grub_env_set(name, value);
440
441 grub_file_close(file);
442 rc = 0;
443
444 return rc;
445 }
446
447 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
448 {
449 (void)ctxt;
450
451 if (argc != 1)
452 {
453 return 1;
454 }
455
456 if (args[0][0] == '1')
457 {
458 grub_iso9660_set_nojoliet(1);
459 }
460 else
461 {
462 grub_iso9660_set_nojoliet(0);
463 }
464
465 return 0;
466 }
467
468 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
469 {
470 int i;
471 int rc = 1;
472 grub_file_t file;
473 grub_uint8_t buf[32];
474
475 (void)ctxt;
476 (void)argc;
477 (void)args;
478
479 if (argc != 1)
480 {
481 return rc;
482 }
483
484 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
485 if (file == NULL)
486 {
487 debug("failed to open file <%s> for udf check\n", args[0]);
488 return 1;
489 }
490
491 for (i = 16; i < 32; i++)
492 {
493 grub_file_seek(file, i * 2048);
494 grub_file_read(file, buf, sizeof(buf));
495 if (buf[0] == 255)
496 {
497 break;
498 }
499 }
500
501 i++;
502 grub_file_seek(file, i * 2048);
503 grub_file_read(file, buf, sizeof(buf));
504
505 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
506 {
507 i++;
508 grub_file_seek(file, i * 2048);
509 grub_file_read(file, buf, sizeof(buf));
510
511 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
512 grub_memcmp(buf + 1, "NSR03", 5) == 0)
513 {
514 rc = 0;
515 }
516 }
517
518 grub_file_close(file);
519
520 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
521
522 return rc;
523 }
524
525 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
526 {
527 long value_long1 = 0;
528 long value_long2 = 0;
529
530 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
531 {
532 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
533 }
534
535 value_long1 = grub_strtol(args[0], NULL, 10);
536 value_long2 = grub_strtol(args[2], NULL, 10);
537
538 if (0 == grub_strcmp(args[1], "eq"))
539 {
540 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
541 }
542 else if (0 == grub_strcmp(args[1], "ne"))
543 {
544 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
545 }
546 else if (0 == grub_strcmp(args[1], "gt"))
547 {
548 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
549 }
550 else if (0 == grub_strcmp(args[1], "lt"))
551 {
552 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
553 }
554 else if (0 == grub_strcmp(args[1], "ge"))
555 {
556 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
557 }
558 else if (0 == grub_strcmp(args[1], "le"))
559 {
560 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
561 }
562 else
563 {
564 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
565 }
566
567 return grub_errno;
568 }
569
570 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
571 {
572 char *pos = NULL;
573 char buf[128] = {0};
574
575 if (argc != 2)
576 {
577 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
578 }
579
580 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
581 pos = grub_strstr(buf, ",");
582 if (pos)
583 {
584 *pos = 0;
585 }
586
587 grub_env_set(args[1], buf);
588
589 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
590 }
591
592 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
593 {
594 int i;
595 char buf[256];
596 grub_disk_t disk;
597 char *pos = NULL;
598 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
599
600 (void)ctxt;
601
602 if (argc != 1)
603 {
604 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
605 }
606
607 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
608 {
609 grub_snprintf(buf, sizeof(buf) - 1, "[ -e %s/%s ]", args[0], files[i]);
610 if (0 == grub_script_execute_sourcecode(buf))
611 {
612 debug("file %s exist, ventoy_compatible YES\n", buf);
613 grub_env_set("ventoy_compatible", "YES");
614 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
615 }
616 else
617 {
618 debug("file %s NOT exist\n", buf);
619 }
620 }
621
622 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
623 pos = grub_strstr(buf, ")");
624 if (pos)
625 {
626 *pos = 0;
627 }
628
629 disk = grub_disk_open(buf);
630 if (disk)
631 {
632 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
633 grub_disk_close(disk);
634
635 g_img_swap_tmp_buf[703] = 0;
636 for (i = 319; i < 703; i++)
637 {
638 if (g_img_swap_tmp_buf[i] == 'V' &&
639 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
640 {
641 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
642 grub_env_set("ventoy_compatible", "YES");
643 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
644 }
645 }
646 }
647 else
648 {
649 debug("failed to open disk <%s>\n", buf);
650 }
651
652 grub_env_set("ventoy_compatible", "NO");
653 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
654 }
655
656 int ventoy_cmp_img(img_info *img1, img_info *img2)
657 {
658 char *s1, *s2;
659 int c1 = 0;
660 int c2 = 0;
661
662 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
663 {
664 c1 = *s1;
665 c2 = *s2;
666
667 if (grub_islower(c1))
668 {
669 c1 = c1 - 'a' + 'A';
670 }
671
672 if (grub_islower(c2))
673 {
674 c2 = c2 - 'a' + 'A';
675 }
676
677 if (c1 != c2)
678 {
679 break;
680 }
681 }
682
683 return (c1 - c2);
684 }
685
686 void ventoy_swap_img(img_info *img1, img_info *img2)
687 {
688 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
689
690 grub_memcpy(img1, img2, sizeof(img_info));
691 img1->next = g_img_swap_tmp.next;
692 img1->prev = g_img_swap_tmp.prev;
693
694 g_img_swap_tmp.next = img2->next;
695 g_img_swap_tmp.prev = img2->prev;
696 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
697 }
698
699 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
700 {
701 grub_size_t i;
702
703 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
704 {
705 return 0;
706 }
707
708 for (i = 0; i < namelen; i++)
709 {
710 if (filename[i] == ' ' || filename[i] == '\t')
711 {
712 return 0;
713 }
714
715 if ((grub_uint8_t)(filename[i]) >= 127)
716 {
717 return 0;
718 }
719 }
720
721 return 1;
722 }
723
724 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
725 {
726 if (0 == info->dir)
727 {
728 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
729 {
730 *((int *)data) = 1;
731 return 0;
732 }
733 }
734
735 return 0;
736 }
737
738 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
739 {
740 int i = 0;
741 int type = 0;
742 int ignore = 0;
743 grub_size_t len;
744 img_info *img;
745 img_info *tail;
746 img_iterator_node *tmp;
747 img_iterator_node *new_node;
748 img_iterator_node *node = (img_iterator_node *)data;
749
750 len = grub_strlen(filename);
751
752 if (info->dir)
753 {
754 if ((len == 1 && filename[0] == '.') ||
755 (len == 2 && filename[0] == '.' && filename[1] == '.'))
756 {
757 return 0;
758 }
759
760 if (!ventoy_img_name_valid(filename, len))
761 {
762 return 0;
763 }
764
765 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
766 {
767 return 0;
768 }
769
770 new_node = grub_zalloc(sizeof(img_iterator_node));
771 if (new_node)
772 {
773 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
774
775 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
776 if (ignore)
777 {
778 debug("Directory %s ignored...\n", new_node->dir);
779 grub_free(new_node);
780 return 0;
781 }
782
783 new_node->tail = node->tail;
784
785 new_node->parent = node;
786 if (!node->firstchild)
787 {
788 node->firstchild = new_node;
789 }
790
791 if (g_img_iterator_tail)
792 {
793 g_img_iterator_tail->next = new_node;
794 g_img_iterator_tail = new_node;
795 }
796 else
797 {
798 g_img_iterator_head.next = new_node;
799 g_img_iterator_tail = new_node;
800 }
801 }
802 }
803 else
804 {
805 debug("Find a file %s\n", filename);
806 if (len <= 4)
807 {
808 return 0;
809 }
810
811 if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
812 {
813 type = img_type_iso;
814 }
815 else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
816 {
817 type = img_type_wim;
818 }
819 #ifdef GRUB_MACHINE_EFI
820 else if (0 == grub_strcasecmp(filename + len - 4, ".efi"))
821 {
822 type = img_type_efi;
823 }
824 #endif
825 else
826 {
827 return 0;
828 }
829
830 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
831 {
832 return 0;
833 }
834
835 img = grub_zalloc(sizeof(img_info));
836 if (img)
837 {
838 img->type = type;
839 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
840
841 for (i = 0; i < (int)len; i++)
842 {
843 if (filename[i] == ' ' || filename[i] == '\t' || (0 == grub_isprint(filename[i])))
844 {
845 img->name[i] = '*';
846 img->unsupport = 1;
847 }
848 }
849
850 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
851
852 img->size = info->size;
853 if (0 == img->size)
854 {
855 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
856 }
857
858 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
859 {
860 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
861 grub_free(img);
862 return 0;
863 }
864
865 if (g_ventoy_img_list)
866 {
867 tail = *(node->tail);
868 img->prev = tail;
869 tail->next = img;
870 }
871 else
872 {
873 g_ventoy_img_list = img;
874 }
875
876 img->id = g_ventoy_img_count;
877 img->parent = node;
878 if (node && NULL == node->firstiso)
879 {
880 node->firstiso = img;
881 }
882
883 node->isocnt++;
884 tmp = node->parent;
885 while (tmp)
886 {
887 tmp->isocnt++;
888 tmp = tmp->parent;
889 }
890
891 *((img_info **)(node->tail)) = img;
892 g_ventoy_img_count++;
893
894 img->alias = ventoy_plugin_get_menu_alias(img->path);
895 img->class = ventoy_plugin_get_menu_class(img->name);
896 if (!img->class)
897 {
898 img->class = g_menu_class[type];
899 }
900 img->menu_prefix = g_menu_prefix[type];
901
902 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
903 }
904 }
905
906 return 0;
907 }
908
909 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
910 {
911 int len = GRUB_UINT_MAX;
912 const char *value = NULL;
913 char name[32] = {0};
914 char plat[32] = {0};
915 char guidstr[32] = {0};
916 ventoy_guid guid = VENTOY_GUID;
917 const char *fmt1 = NULL;
918 const char *fmt2 = NULL;
919 const char *fmt3 = NULL;
920 grub_uint32_t *puint = (grub_uint32_t *)name;
921 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
922 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
923 const char fmtcode[]={
924 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
925 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
926 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
927 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
928 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
929 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
930 };
931
932 grub_memset(name, 0, sizeof(name));
933 puint[0] = grub_swap_bytes32(0x56454e54);
934 puint[3] = grub_swap_bytes32(0x4f4e0000);
935 puint[2] = grub_swap_bytes32(0x45525349);
936 puint[1] = grub_swap_bytes32(0x4f595f56);
937 value = ventoy_get_env(name);
938
939 grub_memset(name, 0, sizeof(name));
940 puint[1] = grub_swap_bytes32(0x5f544f50);
941 puint[0] = grub_swap_bytes32(0x56544c45);
942 fmt1 = ventoy_get_env(name);
943 if (!fmt1)
944 {
945 fmt1 = fmtdata;
946 }
947
948 grub_memset(name, 0, sizeof(name));
949 puint[1] = grub_swap_bytes32(0x5f4c4654);
950 puint[0] = grub_swap_bytes32(0x56544c45);
951 fmt2 = ventoy_get_env(name);
952
953 grub_memset(name, 0, sizeof(name));
954 puint[1] = grub_swap_bytes32(0x5f434c52);
955 puint[0] = grub_swap_bytes32(0x56544c45);
956 fmt3 = ventoy_get_env(name);
957
958 grub_memcpy(guidstr, &guid, sizeof(guid));
959
960 #if defined (GRUB_MACHINE_EFI)
961 puint2[0] = grub_swap_bytes32(0x55454649);
962 #else
963 puint2[0] = grub_swap_bytes32(0x42494f53);
964 #endif
965
966 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
967 #pragma GCC diagnostic push
968 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
969 len = grub_snprintf(buffer, buflen, fmtcode,
970 fmt1 ? fmt1 : fmtdata,
971 fmt2 ? fmt2 : fmtdata + 4,
972 value ? value : "", plat, guidstr,
973 fmt3 ? fmt3 : fmtdata + 6);
974 #pragma GCC diagnostic pop
975
976 grub_memset(name, 0, sizeof(name));
977 puint[0] = grub_swap_bytes32(0x76746f79);
978 puint[2] = grub_swap_bytes32(0x656e7365);
979 puint[1] = grub_swap_bytes32(0x5f6c6963);
980 ventoy_set_env(name, guidstr);
981
982 return len;
983 }
984
985 static img_info * ventoy_get_min_iso(img_iterator_node *node)
986 {
987 img_info *minimg = NULL;
988 img_info *img = (img_info *)(node->firstiso);
989
990 while (img && (img_iterator_node *)(img->parent) == node)
991 {
992 if (img->select == 0 && (NULL == minimg || grub_strcmp(img->name, minimg->name) < 0))
993 {
994 minimg = img;
995 }
996 img = img->next;
997 }
998
999 if (minimg)
1000 {
1001 minimg->select = 1;
1002 }
1003
1004 return minimg;
1005 }
1006
1007 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
1008 {
1009 img_iterator_node *Minchild = NULL;
1010 img_iterator_node *child = node->firstchild;
1011
1012 while (child && child->parent == node)
1013 {
1014 if (child->select == 0 && (NULL == Minchild || grub_strcmp(child->dir, Minchild->dir) < 0))
1015 {
1016 Minchild = child;
1017 }
1018 child = child->next;
1019 }
1020
1021 if (Minchild)
1022 {
1023 Minchild->select = 1;
1024 }
1025
1026 return Minchild;
1027 }
1028
1029 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
1030 {
1031 int offset = 1;
1032 img_info *img;
1033 img_iterator_node *child = NULL;
1034
1035 if (node->isocnt == 0 || node->done == 1)
1036 {
1037 return 0;
1038 }
1039
1040 if (node->parent && node->parent->dirlen < node->dirlen)
1041 {
1042 offset = node->parent->dirlen;
1043 }
1044
1045 if (node == &g_img_iterator_head)
1046 {
1047 if (g_default_menu_mode == 0)
1048 {
1049 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1050 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1051 " echo 'return ...' \n"
1052 "}\n", "<--");
1053 }
1054 }
1055 else
1056 {
1057 node->dir[node->dirlen - 1] = 0;
1058 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1059 "submenu \"%-10s [%s]\" --class=\"vtoydir\" {\n",
1060 "DIR", node->dir + offset);
1061
1062 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1063 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1064 " echo 'return ...' \n"
1065 "}\n", "<--");
1066 }
1067
1068 while ((child = ventoy_get_min_child(node)) != NULL)
1069 {
1070 ventoy_dynamic_tree_menu(child);
1071 }
1072
1073 while ((img = ventoy_get_min_iso(node)) != NULL)
1074 {
1075 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1076 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1077 " %s_%s \n"
1078 "}\n",
1079 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1080 img->unsupport ? "[unsupported] " : "",
1081 img->alias ? img->alias : img->name, img->class, img->id,
1082 img->menu_prefix,
1083 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1084 }
1085
1086 if (node != &g_img_iterator_head)
1087 {
1088 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1089 }
1090
1091 node->done = 1;
1092 return 0;
1093 }
1094
1095 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1096 {
1097 int len;
1098 grub_fs_t fs;
1099 grub_device_t dev = NULL;
1100 img_info *cur = NULL;
1101 img_info *tail = NULL;
1102 img_info *default_node = NULL;
1103 const char *strdata = NULL;
1104 char *device_name = NULL;
1105 const char *default_image = NULL;
1106 int img_len = 0;
1107 char buf[32];
1108 img_iterator_node *node = NULL;
1109 img_iterator_node *tmp = NULL;
1110
1111 (void)ctxt;
1112
1113 if (argc != 2)
1114 {
1115 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1116 }
1117
1118 if (g_ventoy_img_list || g_ventoy_img_count)
1119 {
1120 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1121 }
1122
1123 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1124 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1125 {
1126 g_filt_dot_underscore_file = 1;
1127 }
1128
1129 device_name = grub_file_get_device_name(args[0]);
1130 if (!device_name)
1131 {
1132 goto fail;
1133 }
1134
1135 g_enum_dev = dev = grub_device_open(device_name);
1136 if (!dev)
1137 {
1138 goto fail;
1139 }
1140
1141 g_enum_fs = fs = grub_fs_probe(dev);
1142 if (!fs)
1143 {
1144 goto fail;
1145 }
1146
1147 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1148 {
1149 debug("unsupported fs:<%s>\n", fs->name);
1150 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1151 goto fail;
1152 }
1153
1154 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1155 if (strdata && strdata[0] == '1')
1156 {
1157 g_default_menu_mode = 1;
1158 }
1159
1160 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
1161
1162 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
1163
1164 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1165 if (strdata && strdata[0] == '/')
1166 {
1167 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
1168 if (g_img_iterator_head.dir[len - 1] != '/')
1169 {
1170 g_img_iterator_head.dir[len++] = '/';
1171 }
1172 g_img_iterator_head.dirlen = len;
1173 }
1174 else
1175 {
1176 g_img_iterator_head.dirlen = 1;
1177 grub_strcpy(g_img_iterator_head.dir, "/");
1178 }
1179
1180 g_img_iterator_head.tail = &tail;
1181
1182 for (node = &g_img_iterator_head; node; node = node->next)
1183 {
1184 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1185 }
1186
1187 for (node = &g_img_iterator_head; node; node = node->next)
1188 {
1189 ventoy_dynamic_tree_menu(node);
1190 }
1191
1192 /* free node */
1193 node = g_img_iterator_head.next;
1194 while (node)
1195 {
1196 tmp = node->next;
1197 grub_free(node);
1198 node = tmp;
1199 }
1200
1201 /* sort image list by image name */
1202 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1203 {
1204 for (tail = cur->next; tail; tail = tail->next)
1205 {
1206 if (ventoy_cmp_img(cur, tail) > 0)
1207 {
1208 ventoy_swap_img(cur, tail);
1209 }
1210 }
1211 }
1212
1213 if (g_default_menu_mode == 1)
1214 {
1215 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1216 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1217 " echo 'return ...' \n"
1218 "}\n", "<--");
1219 }
1220
1221 if (g_default_menu_mode == 0)
1222 {
1223 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1224 if (default_image)
1225 {
1226 img_len = grub_strlen(default_image);
1227 }
1228 }
1229
1230 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1231 {
1232 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1233 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1234 " %s_%s \n"
1235 "}\n",
1236 cur->unsupport ? "[unsupported] " : "",
1237 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
1238 cur->menu_prefix,
1239 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
1240
1241 if (g_default_menu_mode == 0 && default_image && default_node == NULL)
1242 {
1243 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1244 {
1245 default_node = cur;
1246 }
1247 }
1248 }
1249
1250 if (default_node)
1251 {
1252 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1253 }
1254
1255 g_list_script_buf[g_list_script_pos] = 0;
1256
1257 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1258 grub_env_set(args[1], buf);
1259
1260 fail:
1261
1262 check_free(device_name, grub_free);
1263 check_free(dev, grub_device_close);
1264
1265 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1266 }
1267
1268
1269 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1270 {
1271 img_info *next = NULL;
1272 img_info *cur = g_ventoy_img_list;
1273
1274 (void)ctxt;
1275 (void)argc;
1276 (void)args;
1277
1278 while (cur)
1279 {
1280 next = cur->next;
1281 grub_free(cur);
1282 cur = next;
1283 }
1284
1285 g_ventoy_img_list = NULL;
1286 g_ventoy_img_count = 0;
1287
1288 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1289 }
1290
1291 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1292 {
1293 long img_id = 0;
1294 img_info *cur = g_ventoy_img_list;
1295
1296 (void)ctxt;
1297
1298 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1299 {
1300 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
1301 }
1302
1303 img_id = grub_strtol(args[0], NULL, 10);
1304 if (img_id >= g_ventoy_img_count)
1305 {
1306 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
1307 }
1308
1309 debug("Find image %ld name \n", img_id);
1310
1311 while (cur && img_id > 0)
1312 {
1313 img_id--;
1314 cur = cur->next;
1315 }
1316
1317 if (!cur)
1318 {
1319 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
1320 }
1321
1322 debug("image name is %s\n", cur->name);
1323
1324 grub_env_set(args[1], cur->name);
1325
1326 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1327 }
1328
1329 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
1330 {
1331 int img_id = 0;
1332 char *pos = NULL;
1333 const char *id = NULL;
1334 img_info *cur = g_ventoy_img_list;
1335
1336 (void)ctxt;
1337
1338 if (argc != 1)
1339 {
1340 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
1341 }
1342
1343 id = grub_env_get("chosen");
1344
1345 pos = grub_strstr(id, "VID_");
1346 if (pos)
1347 {
1348 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
1349 }
1350 else
1351 {
1352 img_id = (int)grub_strtoul(id, NULL, 10);
1353 }
1354
1355 while (cur)
1356 {
1357 if (img_id == cur->id)
1358 {
1359 break;
1360 }
1361 cur = cur->next;
1362 }
1363
1364 if (!cur)
1365 {
1366 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
1367 }
1368
1369 grub_env_set(args[0], cur->path);
1370
1371 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1372 }
1373
1374 static int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
1375 {
1376 grub_disk_t disk;
1377 char *device_name;
1378 char *pos;
1379 char *pos2;
1380
1381 device_name = grub_file_get_device_name(filename);
1382 if (!device_name)
1383 {
1384 return 1;
1385 }
1386
1387 pos = device_name;
1388 if (pos[0] == '(')
1389 {
1390 pos++;
1391 }
1392
1393 pos2 = grub_strstr(pos, ",");
1394 if (!pos2)
1395 {
1396 pos2 = grub_strstr(pos, ")");
1397 }
1398
1399 if (pos2)
1400 {
1401 *pos2 = 0;
1402 }
1403
1404 disk = grub_disk_open(pos);
1405 if (disk)
1406 {
1407 grub_disk_read(disk, 0, 0x180, 16, guid);
1408 grub_disk_close(disk);
1409 }
1410 else
1411 {
1412 return 1;
1413 }
1414
1415 grub_free(device_name);
1416 return 0;
1417 }
1418
1419 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
1420 {
1421 eltorito_descriptor desc;
1422
1423 grub_memset(&desc, 0, sizeof(desc));
1424 grub_file_seek(file, 17 * 2048);
1425 grub_file_read(file, &desc, sizeof(desc));
1426
1427 if (desc.type != 0 || desc.version != 1)
1428 {
1429 return 0;
1430 }
1431
1432 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
1433 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
1434 {
1435 return 0;
1436 }
1437
1438 return desc.sector;
1439 }
1440
1441 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
1442 {
1443 int i;
1444 grub_uint8_t buf[512];
1445
1446 grub_file_seek(file, sector * 2048);
1447 grub_file_read(file, buf, sizeof(buf));
1448
1449 if (buf[0] == 0x01 && buf[1] == 0xEF)
1450 {
1451 debug("%s efi eltorito in Validation Entry\n", file->name);
1452 return 1;
1453 }
1454
1455 for (i = 64; i < (int)sizeof(buf); i += 32)
1456 {
1457 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
1458 {
1459 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1460 return 1;
1461 }
1462 }
1463
1464 debug("%s does not contain efi eltorito\n", file->name);
1465 return 0;
1466 }
1467
1468 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1469 {
1470 char *pos;
1471 const char *fs = NULL;
1472 const char *cdprompt = NULL;
1473 grub_uint32_t i;
1474 grub_uint8_t chksum = 0;
1475 grub_disk_t disk;
1476
1477 disk = file->device->disk;
1478 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1479
1480 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1481 param->vtoy_disk_part_id = disk->partition->number + 1;
1482 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
1483
1484 pos = grub_strstr(file->name, "/");
1485 if (!pos)
1486 {
1487 pos = file->name;
1488 }
1489
1490 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1491
1492 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1493
1494 param->vtoy_img_size = file->size;
1495
1496 param->vtoy_reserved[0] = g_ventoy_break_level;
1497 param->vtoy_reserved[1] = g_ventoy_debug_level;
1498
1499 param->vtoy_reserved[2] = g_ventoy_chain_type;
1500
1501 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1502 param->vtoy_reserved[4] = 0;
1503 if (g_ventoy_chain_type == 1) /* Windows */
1504 {
1505 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1506 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
1507 {
1508 param->vtoy_reserved[4] = 1;
1509 }
1510 }
1511
1512 fs = ventoy_get_env("ventoy_fs_probe");
1513 if (fs && grub_strcmp(fs, "udf") == 0)
1514 {
1515 param->vtoy_reserved[3] = 1;
1516 }
1517
1518 /* calculate checksum */
1519 for (i = 0; i < sizeof(ventoy_os_param); i++)
1520 {
1521 chksum += *((grub_uint8_t *)param + i);
1522 }
1523 param->chksum = (grub_uint8_t)(0x100 - chksum);
1524
1525 return;
1526 }
1527
1528 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1529 {
1530 grub_uint32_t i = 0;
1531 grub_uint64_t total = 0;
1532 ventoy_img_chunk *chunk = NULL;
1533
1534 for (i = 0; i < chunklist->cur_chunk; i++)
1535 {
1536 chunk = chunklist->chunk + i;
1537
1538 if (chunk->disk_start_sector <= start)
1539 {
1540 debug("%u disk start invalid %lu\n", i, (ulong)start);
1541 return 1;
1542 }
1543
1544 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
1545 }
1546
1547 if (total != ((file->size + 511) / 512))
1548 {
1549 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
1550 return 1;
1551 }
1552
1553 return 0;
1554 }
1555
1556 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1557 {
1558 int fs_type;
1559 grub_uint32_t i = 0;
1560 grub_uint32_t sector = 0;
1561 grub_uint32_t count = 0;
1562 grub_off_t size = 0;
1563 grub_off_t read = 0;
1564
1565 fs_type = ventoy_get_fs_type(file->fs->name);
1566 if (fs_type == ventoy_fs_exfat)
1567 {
1568 grub_fat_get_file_chunk(start, file, chunklist);
1569 }
1570 else if (fs_type == ventoy_fs_ext)
1571 {
1572 grub_ext_get_file_chunk(start, file, chunklist);
1573 }
1574 else
1575 {
1576 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
1577 file->read_hook_data = chunklist;
1578
1579 for (size = file->size; size > 0; size -= read)
1580 {
1581 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
1582 grub_file_read(file, NULL, read);
1583 }
1584
1585 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
1586 {
1587 chunklist->chunk[i].disk_start_sector += start;
1588 chunklist->chunk[i].disk_end_sector += start;
1589 }
1590
1591 if (ventoy_fs_udf == fs_type)
1592 {
1593 for (i = 0; i < chunklist->cur_chunk; i++)
1594 {
1595 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
1596 chunklist->chunk[i].img_start_sector = sector;
1597 chunklist->chunk[i].img_end_sector = sector + count - 1;
1598 sector += count;
1599 }
1600 }
1601 }
1602
1603 return 0;
1604 }
1605
1606 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1607 {
1608 int rc;
1609 grub_file_t file;
1610 grub_disk_addr_t start;
1611
1612 (void)ctxt;
1613 (void)argc;
1614
1615 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1616 if (!file)
1617 {
1618 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1619 }
1620
1621 if (g_img_chunk_list.chunk)
1622 {
1623 grub_free(g_img_chunk_list.chunk);
1624 }
1625
1626 /* get image chunk data */
1627 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1628 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1629 if (NULL == g_img_chunk_list.chunk)
1630 {
1631 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1632 }
1633
1634 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1635 g_img_chunk_list.cur_chunk = 0;
1636
1637 start = file->device->disk->partition->start;
1638
1639 ventoy_get_block_list(file, &g_img_chunk_list, start);
1640
1641 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
1642 grub_file_close(file);
1643
1644 if (rc)
1645 {
1646 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
1647 }
1648
1649 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1650 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1651 }
1652
1653 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1654 {
1655 int i = 0;
1656 int pos = 0;
1657 char *buf = NULL;
1658 char configfile[128];
1659 install_template *node = NULL;
1660
1661 (void)ctxt;
1662 (void)argc;
1663 (void)args;
1664
1665 debug("select auto installation %d\n", argc);
1666
1667 if (argc < 1)
1668 {
1669 return 0;
1670 }
1671
1672 node = ventoy_plugin_find_install_template(args[0]);
1673 if (!node)
1674 {
1675 debug("Install template not found for %s\n", args[0]);
1676 return 0;
1677 }
1678
1679 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
1680 if (!buf)
1681 {
1682 return 0;
1683 }
1684
1685 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
1686 " echo %s\n}\n", "123");
1687
1688 for (i = 0; i < node->templatenum; i++)
1689 {
1690 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
1691 " echo 123\n}\n",
1692 node->templatepath[i].path);
1693 }
1694
1695 g_ventoy_menu_esc = 1;
1696 g_ventoy_suppress_esc = 1;
1697
1698 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
1699 grub_script_execute_sourcecode(configfile);
1700
1701 g_ventoy_menu_esc = 0;
1702 g_ventoy_suppress_esc = 0;
1703
1704 grub_free(buf);
1705
1706 node->cursel = g_ventoy_last_entry - 1;
1707
1708 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1709 }
1710
1711 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
1712 {
1713 int i = 0;
1714 int pos = 0;
1715 char *buf = NULL;
1716 char configfile[128];
1717 persistence_config *node;
1718
1719 (void)ctxt;
1720 (void)argc;
1721 (void)args;
1722
1723 debug("select persistece %d\n", argc);
1724
1725 if (argc < 1)
1726 {
1727 return 0;
1728 }
1729
1730 node = ventoy_plugin_find_persistent(args[0]);
1731 if (!node)
1732 {
1733 debug("Persistence image not found for %s\n", args[0]);
1734 return 0;
1735 }
1736
1737 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
1738 if (!buf)
1739 {
1740 return 0;
1741 }
1742
1743 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
1744 " echo %s\n}\n", "123");
1745
1746 for (i = 0; i < node->backendnum; i++)
1747 {
1748 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
1749 " echo 123\n}\n",
1750 node->backendpath[i].path);
1751
1752 }
1753
1754 g_ventoy_menu_esc = 1;
1755 g_ventoy_suppress_esc = 1;
1756
1757 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
1758 grub_script_execute_sourcecode(configfile);
1759
1760 g_ventoy_menu_esc = 0;
1761 g_ventoy_suppress_esc = 0;
1762
1763 grub_free(buf);
1764
1765 node->cursel = g_ventoy_last_entry - 1;
1766
1767 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1768 }
1769
1770 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1771 {
1772 grub_uint32_t i;
1773 ventoy_img_chunk *cur;
1774
1775 (void)ctxt;
1776 (void)argc;
1777 (void)args;
1778
1779 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
1780 {
1781 cur = g_img_chunk_list.chunk + i;
1782 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1783 cur->img_start_sector, cur->img_end_sector,
1784 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
1785 );
1786 }
1787
1788 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1789 }
1790
1791 #ifdef GRUB_MACHINE_EFI
1792 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1793 {
1794 (void)ctxt;
1795 (void)argc;
1796 (void)args;
1797 return 0;
1798 }
1799 #else
1800 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1801 {
1802 int rc = 0;
1803 ulong chain_len = 0;
1804 char *chain_data = NULL;
1805 char *relocator_addr = NULL;
1806 grub_relocator_chunk_t ch;
1807 struct grub_relocator *relocator = NULL;
1808 char envbuf[64] = { 0 };
1809
1810 (void)ctxt;
1811 (void)argc;
1812 (void)args;
1813
1814 if (argc != 2)
1815 {
1816 return 1;
1817 }
1818
1819 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
1820 chain_len = grub_strtoul(args[1], NULL, 10);
1821
1822 relocator = grub_relocator_new ();
1823 if (!relocator)
1824 {
1825 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
1826 return 1;
1827 }
1828
1829 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
1830 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1831 chain_len);
1832 if (rc)
1833 {
1834 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
1835 grub_relocator_unload (relocator);
1836 return 1;
1837 }
1838
1839 relocator_addr = get_virtual_current_address(ch);
1840
1841 grub_memcpy(relocator_addr, chain_data, chain_len);
1842
1843 grub_relocator_unload (relocator);
1844
1845 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
1846 grub_env_set("vtoy_chain_relocator_addr", envbuf);
1847
1848 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1849 }
1850 #endif
1851
1852 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
1853 {
1854 grub_uint32_t i;
1855 grub_file_t file;
1856 ventoy_img_chunk_list chunklist;
1857
1858 (void)ctxt;
1859 (void)argc;
1860
1861 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1862 if (!file)
1863 {
1864 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1865 }
1866
1867 /* get image chunk data */
1868 grub_memset(&chunklist, 0, sizeof(chunklist));
1869 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1870 if (NULL == chunklist.chunk)
1871 {
1872 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1873 }
1874
1875 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
1876 chunklist.cur_chunk = 0;
1877
1878 ventoy_get_block_list(file, &chunklist, 0);
1879
1880 if (0 != ventoy_check_block_list(file, &chunklist, 0))
1881 {
1882 grub_printf("########## UNSUPPORTED ###############\n");
1883 }
1884
1885 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
1886
1887 for (i = 0; i < chunklist.cur_chunk; i++)
1888 {
1889 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
1890 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
1891 }
1892
1893 grub_printf("\n==================================\n");
1894
1895 for (i = 0; i < chunklist.cur_chunk; i++)
1896 {
1897 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
1898 (ulonglong)chunklist.chunk[i].img_start_sector,
1899 (ulonglong)chunklist.chunk[i].img_end_sector,
1900 (ulonglong)chunklist.chunk[i].disk_start_sector,
1901 (ulonglong)chunklist.chunk[i].disk_end_sector
1902 );
1903 }
1904
1905 grub_free(chunklist.chunk);
1906 grub_file_close(file);
1907
1908 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1909 }
1910
1911 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
1912 {
1913 int i;
1914 ventoy_grub_param_file_replace *replace = NULL;
1915
1916 (void)ctxt;
1917 (void)argc;
1918 (void)args;
1919
1920 if (argc >= 2)
1921 {
1922 replace = &(g_grub_param->file_replace);
1923 replace->magic = GRUB_FILE_REPLACE_MAGIC;
1924
1925 replace->old_name_cnt = 0;
1926 for (i = 0; i < 4 && i + 1 < argc; i++)
1927 {
1928 replace->old_name_cnt++;
1929 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
1930 }
1931
1932 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
1933 }
1934
1935 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1936 }
1937
1938 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1939 {
1940 (void)ctxt;
1941 (void)argc;
1942 (void)args;
1943
1944 if (argc == 0)
1945 {
1946 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
1947 grub_printf("%s", g_list_script_buf);
1948 }
1949 else
1950 {
1951 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
1952 grub_printf("%s", g_tree_script_buf);
1953 }
1954
1955 return 0;
1956 }
1957
1958 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
1959 {
1960 img_info *cur = g_ventoy_img_list;
1961
1962 (void)ctxt;
1963 (void)argc;
1964 (void)args;
1965
1966 while (cur)
1967 {
1968 grub_printf("path:<%s> id=%d\n", cur->path, cur->id);
1969 grub_printf("name:<%s>\n\n", cur->name);
1970 cur = cur->next;
1971 }
1972
1973 return 0;
1974 }
1975
1976 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1977 {
1978 (void)ctxt;
1979 (void)argc;
1980 (void)args;
1981
1982 {
1983 grub_file_t file;
1984 char *buf;
1985 char name[128];
1986
1987 file = grub_file_open("(hd0,1)/ventoy/ventoy.disk.img.xz", GRUB_FILE_TYPE_NONE);
1988 if (file)
1989 {
1990 grub_printf("Open File OK (size:%llu)\n", (ulonglong)file->size);
1991
1992 buf = grub_malloc(file->size);
1993 grub_file_read(file, buf, file->size);
1994
1995 grub_file_close(file);
1996
1997 grub_snprintf(name, sizeof(name), "mem:0x%llx:size:%llu", (ulonglong)(ulong)buf, (ulonglong)file->size);
1998 grub_printf("<%s>\n", name);
1999 }
2000 }
2001
2002
2003 ventoy_plugin_dump_auto_install();
2004
2005 return 0;
2006 }
2007
2008 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2009 {
2010 (void)ctxt;
2011 (void)argc;
2012 (void)args;
2013
2014 ventoy_plugin_dump_persistence();
2015
2016 return 0;
2017 }
2018
2019 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2020 {
2021 (void)ctxt;
2022 (void)argc;
2023 (void)args;
2024
2025 if (argc != 1)
2026 {
2027 return 1;
2028 }
2029
2030 if (args[0][0] == '0')
2031 {
2032 return g_ventoy_memdisk_mode ? 0 : 1;
2033 }
2034 else if (args[0][0] == '1')
2035 {
2036 return g_ventoy_iso_raw ? 0 : 1;
2037 }
2038 else if (args[0][0] == '2')
2039 {
2040 return g_ventoy_iso_uefi_drv ? 0 : 1;
2041 }
2042
2043 return 1;
2044 }
2045
2046 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2047 {
2048 static int configfile_mode = 0;
2049 char memfile[128] = {0};
2050
2051 (void)ctxt;
2052 (void)argc;
2053 (void)args;
2054
2055 /*
2056 * args[0]: 0:normal 1:configfile
2057 * args[1]: 0:list_buf 1:tree_buf
2058 */
2059
2060 if (argc != 2)
2061 {
2062 debug("Invalid argc %d\n", argc);
2063 return 0;
2064 }
2065
2066 if (args[0][0] == '0')
2067 {
2068 if (args[1][0] == '0')
2069 {
2070 grub_script_execute_sourcecode(g_list_script_buf);
2071 }
2072 else
2073 {
2074 grub_script_execute_sourcecode(g_tree_script_buf);
2075 }
2076 }
2077 else
2078 {
2079 if (configfile_mode)
2080 {
2081 debug("Now already in F3 mode %d\n", configfile_mode);
2082 return 0;
2083 }
2084
2085 if (args[1][0] == '0')
2086 {
2087 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2088 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2089 }
2090 else
2091 {
2092 g_ventoy_last_entry = -1;
2093 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2094 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2095 }
2096
2097 configfile_mode = 1;
2098 grub_script_execute_sourcecode(memfile);
2099 configfile_mode = 0;
2100 }
2101
2102 return 0;
2103 }
2104
2105 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2106 {
2107 grub_file_t file;
2108
2109 (void)ctxt;
2110
2111 if (argc != 1)
2112 {
2113 return 1;
2114 }
2115
2116 g_ventoy_case_insensitive = 1;
2117 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2118 g_ventoy_case_insensitive = 0;
2119
2120 grub_errno = 0;
2121
2122 if (file)
2123 {
2124 grub_file_close(file);
2125 return 0;
2126 }
2127 return 1;
2128 }
2129
2130 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
2131 {
2132 int id = 0;
2133 int find = 0;
2134 grub_disk_t disk;
2135 const char *isopath = NULL;
2136 char hdname[32];
2137 ventoy_mbr_head mbr;
2138
2139 (void)ctxt;
2140 (void)argc;
2141
2142 if (argc != 1)
2143 {
2144 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
2145 }
2146
2147 isopath = grub_env_get("iso_path");
2148 if (!isopath)
2149 {
2150 debug("isopath is null %p\n", isopath);
2151 return 0;
2152 }
2153
2154 debug("isopath is %s\n", isopath);
2155
2156 for (id = 0; id < 30 && (find == 0); id++)
2157 {
2158 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
2159 if (grub_strstr(isopath, hdname))
2160 {
2161 debug("skip %s ...\n", hdname);
2162 continue;
2163 }
2164
2165 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
2166
2167 disk = grub_disk_open(hdname);
2168 if (!disk)
2169 {
2170 debug("%s not exist\n", hdname);
2171 break;
2172 }
2173
2174 grub_memset(&mbr, 0, sizeof(mbr));
2175 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
2176 {
2177 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
2178 {
2179 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
2180 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
2181 {
2182
2183 grub_env_set(args[0], hdname);
2184 find = 1;
2185 }
2186 }
2187 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
2188 }
2189 else
2190 {
2191 debug("read %s failed\n", hdname);
2192 }
2193
2194 grub_disk_close(disk);
2195 }
2196
2197 return 0;
2198 }
2199
2200 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
2201 {
2202 grub_uint64_t size = 0;
2203 grub_file_t file;
2204 va_list ap;
2205 char fullpath[256] = {0};
2206
2207 va_start (ap, fmt);
2208 grub_vsnprintf(fullpath, 255, fmt, ap);
2209 va_end (ap);
2210
2211 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
2212 if (!file)
2213 {
2214 debug("grub_file_open failed <%s>\n", fullpath);
2215 grub_errno = 0;
2216 return 0;
2217 }
2218
2219 size = file->size;
2220 grub_file_close(file);
2221 return size;
2222 }
2223
2224 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
2225 {
2226 va_list ap;
2227 grub_file_t file;
2228 char fullpath[256] = {0};
2229
2230 va_start (ap, fmt);
2231 grub_vsnprintf(fullpath, 255, fmt, ap);
2232 va_end (ap);
2233
2234 file = grub_file_open(fullpath, type);
2235 if (!file)
2236 {
2237 debug("grub_file_open failed <%s>\n", fullpath);
2238 grub_errno = 0;
2239 }
2240
2241 return file;
2242 }
2243
2244 int ventoy_is_file_exist(const char *fmt, ...)
2245 {
2246 va_list ap;
2247 int len;
2248 char *pos = NULL;
2249 char buf[256] = {0};
2250
2251 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
2252 pos = buf + 5;
2253
2254 va_start (ap, fmt);
2255 len = grub_vsnprintf(pos, 255, fmt, ap);
2256 va_end (ap);
2257
2258 grub_strncpy(pos + len, " ]", 2);
2259
2260 debug("script exec %s\n", buf);
2261
2262 if (0 == grub_script_execute_sourcecode(buf))
2263 {
2264 return 1;
2265 }
2266
2267 return 0;
2268 }
2269
2270 static int ventoy_env_init(void)
2271 {
2272 char buf[64];
2273
2274 grub_env_set("vtdebug_flag", "");
2275 grub_env_export("vtdebug_flag");
2276
2277
2278
2279 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2280 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2281
2282 ventoy_filt_register(0, ventoy_wrapper_open);
2283
2284 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
2285 if (g_grub_param)
2286 {
2287 g_grub_param->grub_env_get = grub_env_get;
2288 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
2289 grub_env_set("env_param", buf);
2290 }
2291
2292 return 0;
2293 }
2294
2295 static cmd_para ventoy_cmds[] =
2296 {
2297 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
2298 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2299 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2300 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
2301 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
2302 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
2303 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
2304 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
2305 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
2306 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
2307 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
2308 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
2309 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
2310 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
2311 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
2312 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
2313 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
2314 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
2315 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
2316 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
2317 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
2318 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
2319 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
2320 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
2321
2322 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
2323 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
2324 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
2325 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
2326
2327 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2328 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2329 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
2330 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
2331 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
2332 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
2333 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
2334 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
2335 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
2336 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
2337
2338 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
2339 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
2340 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
2341 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
2342 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
2343 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
2344 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
2345
2346 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
2347 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
2348 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
2349 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
2350
2351
2352 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
2353 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
2354
2355 };
2356
2357
2358
2359 GRUB_MOD_INIT(ventoy)
2360 {
2361 grub_uint32_t i;
2362 cmd_para *cur = NULL;
2363
2364 ventoy_env_init();
2365
2366 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2367 {
2368 cur = ventoy_cmds + i;
2369 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
2370 cur->summary, cur->description, cur->parser);
2371 }
2372 }
2373
2374 GRUB_MOD_FINI(ventoy)
2375 {
2376 grub_uint32_t i;
2377
2378 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2379 {
2380 grub_unregister_extcmd(ventoy_cmds[i].cmd);
2381 }
2382 }
2383