]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
1a433edb5c4e6d4338d3417e5bf99159a4bf933e
[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(vtoy_alias_image_file, img->path);
895 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, 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 = NULL;
1033 const char *dir_class = NULL;
1034 const char *dir_alias = NULL;
1035 img_iterator_node *child = NULL;
1036
1037 if (node->isocnt == 0 || node->done == 1)
1038 {
1039 return 0;
1040 }
1041
1042 if (node->parent && node->parent->dirlen < node->dirlen)
1043 {
1044 offset = node->parent->dirlen;
1045 }
1046
1047 if (node == &g_img_iterator_head)
1048 {
1049 if (g_default_menu_mode == 0)
1050 {
1051 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1052 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1053 " echo 'return ...' \n"
1054 "}\n", "<--");
1055 }
1056 }
1057 else
1058 {
1059 node->dir[node->dirlen - 1] = 0;
1060 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir);
1061 if (!dir_class)
1062 {
1063 dir_class = "vtoydir";
1064 }
1065
1066 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
1067 if (dir_alias)
1068 {
1069 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1070 "submenu \"%-10s %s\" --class=\"%s\" {\n",
1071 "DIR", dir_alias, dir_class);
1072 }
1073 else
1074 {
1075 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1076 "submenu \"%-10s [%s]\" --class=\"%s\" {\n",
1077 "DIR", node->dir + offset, dir_class);
1078 }
1079
1080 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1081 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1082 " echo 'return ...' \n"
1083 "}\n", "<--");
1084 }
1085
1086 while ((child = ventoy_get_min_child(node)) != NULL)
1087 {
1088 ventoy_dynamic_tree_menu(child);
1089 }
1090
1091 while ((img = ventoy_get_min_iso(node)) != NULL)
1092 {
1093 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
1094 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1095 " %s_%s \n"
1096 "}\n",
1097 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
1098 img->unsupport ? "[unsupported] " : "",
1099 img->alias ? img->alias : img->name, img->class, img->id,
1100 img->menu_prefix,
1101 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
1102 }
1103
1104 if (node != &g_img_iterator_head)
1105 {
1106 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
1107 }
1108
1109 node->done = 1;
1110 return 0;
1111 }
1112
1113 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
1114 {
1115 int len;
1116 grub_fs_t fs;
1117 grub_device_t dev = NULL;
1118 img_info *cur = NULL;
1119 img_info *tail = NULL;
1120 img_info *default_node = NULL;
1121 const char *strdata = NULL;
1122 char *device_name = NULL;
1123 const char *default_image = NULL;
1124 int img_len = 0;
1125 char buf[32];
1126 img_iterator_node *node = NULL;
1127 img_iterator_node *tmp = NULL;
1128
1129 (void)ctxt;
1130
1131 if (argc != 2)
1132 {
1133 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
1134 }
1135
1136 if (g_ventoy_img_list || g_ventoy_img_count)
1137 {
1138 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
1139 }
1140
1141 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1142 if (strdata && strdata[0] == '1' && strdata[1] == 0)
1143 {
1144 g_filt_dot_underscore_file = 1;
1145 }
1146
1147 device_name = grub_file_get_device_name(args[0]);
1148 if (!device_name)
1149 {
1150 goto fail;
1151 }
1152
1153 g_enum_dev = dev = grub_device_open(device_name);
1154 if (!dev)
1155 {
1156 goto fail;
1157 }
1158
1159 g_enum_fs = fs = grub_fs_probe(dev);
1160 if (!fs)
1161 {
1162 goto fail;
1163 }
1164
1165 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
1166 {
1167 debug("unsupported fs:<%s>\n", fs->name);
1168 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1169 goto fail;
1170 }
1171
1172 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1173 if (strdata && strdata[0] == '1')
1174 {
1175 g_default_menu_mode = 1;
1176 }
1177
1178 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
1179
1180 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
1181
1182 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1183 if (strdata && strdata[0] == '/')
1184 {
1185 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
1186 if (g_img_iterator_head.dir[len - 1] != '/')
1187 {
1188 g_img_iterator_head.dir[len++] = '/';
1189 }
1190 g_img_iterator_head.dirlen = len;
1191 }
1192 else
1193 {
1194 g_img_iterator_head.dirlen = 1;
1195 grub_strcpy(g_img_iterator_head.dir, "/");
1196 }
1197
1198 g_img_iterator_head.tail = &tail;
1199
1200 for (node = &g_img_iterator_head; node; node = node->next)
1201 {
1202 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1203 }
1204
1205 for (node = &g_img_iterator_head; node; node = node->next)
1206 {
1207 ventoy_dynamic_tree_menu(node);
1208 }
1209
1210 /* free node */
1211 node = g_img_iterator_head.next;
1212 while (node)
1213 {
1214 tmp = node->next;
1215 grub_free(node);
1216 node = tmp;
1217 }
1218
1219 /* sort image list by image name */
1220 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1221 {
1222 for (tail = cur->next; tail; tail = tail->next)
1223 {
1224 if (ventoy_cmp_img(cur, tail) > 0)
1225 {
1226 ventoy_swap_img(cur, tail);
1227 }
1228 }
1229 }
1230
1231 if (g_default_menu_mode == 1)
1232 {
1233 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1234 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1235 " echo 'return ...' \n"
1236 "}\n", "<--");
1237 }
1238
1239 if (g_default_menu_mode == 0)
1240 {
1241 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
1242 if (default_image)
1243 {
1244 img_len = grub_strlen(default_image);
1245 }
1246 }
1247
1248 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1249 {
1250 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
1251 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1252 " %s_%s \n"
1253 "}\n",
1254 cur->unsupport ? "[unsupported] " : "",
1255 cur->alias ? cur->alias : cur->name, cur->class, cur->id,
1256 cur->menu_prefix,
1257 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
1258
1259 if (g_default_menu_mode == 0 && default_image && default_node == NULL)
1260 {
1261 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
1262 {
1263 default_node = cur;
1264 }
1265 }
1266 }
1267
1268 if (default_node)
1269 {
1270 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id);
1271 }
1272
1273 g_list_script_buf[g_list_script_pos] = 0;
1274
1275 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1276 grub_env_set(args[1], buf);
1277
1278 fail:
1279
1280 check_free(device_name, grub_free);
1281 check_free(dev, grub_device_close);
1282
1283 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1284 }
1285
1286
1287 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1288 {
1289 img_info *next = NULL;
1290 img_info *cur = g_ventoy_img_list;
1291
1292 (void)ctxt;
1293 (void)argc;
1294 (void)args;
1295
1296 while (cur)
1297 {
1298 next = cur->next;
1299 grub_free(cur);
1300 cur = next;
1301 }
1302
1303 g_ventoy_img_list = NULL;
1304 g_ventoy_img_count = 0;
1305
1306 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1307 }
1308
1309 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1310 {
1311 long img_id = 0;
1312 img_info *cur = g_ventoy_img_list;
1313
1314 (void)ctxt;
1315
1316 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1317 {
1318 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
1319 }
1320
1321 img_id = grub_strtol(args[0], NULL, 10);
1322 if (img_id >= g_ventoy_img_count)
1323 {
1324 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
1325 }
1326
1327 debug("Find image %ld name \n", img_id);
1328
1329 while (cur && img_id > 0)
1330 {
1331 img_id--;
1332 cur = cur->next;
1333 }
1334
1335 if (!cur)
1336 {
1337 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
1338 }
1339
1340 debug("image name is %s\n", cur->name);
1341
1342 grub_env_set(args[1], cur->name);
1343
1344 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1345 }
1346
1347 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
1348 {
1349 int img_id = 0;
1350 char *pos = NULL;
1351 const char *id = NULL;
1352 img_info *cur = g_ventoy_img_list;
1353
1354 (void)ctxt;
1355
1356 if (argc != 1)
1357 {
1358 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
1359 }
1360
1361 id = grub_env_get("chosen");
1362
1363 pos = grub_strstr(id, "VID_");
1364 if (pos)
1365 {
1366 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
1367 }
1368 else
1369 {
1370 img_id = (int)grub_strtoul(id, NULL, 10);
1371 }
1372
1373 while (cur)
1374 {
1375 if (img_id == cur->id)
1376 {
1377 break;
1378 }
1379 cur = cur->next;
1380 }
1381
1382 if (!cur)
1383 {
1384 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
1385 }
1386
1387 grub_env_set(args[0], cur->path);
1388
1389 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1390 }
1391
1392 static int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
1393 {
1394 grub_disk_t disk;
1395 char *device_name;
1396 char *pos;
1397 char *pos2;
1398
1399 device_name = grub_file_get_device_name(filename);
1400 if (!device_name)
1401 {
1402 return 1;
1403 }
1404
1405 pos = device_name;
1406 if (pos[0] == '(')
1407 {
1408 pos++;
1409 }
1410
1411 pos2 = grub_strstr(pos, ",");
1412 if (!pos2)
1413 {
1414 pos2 = grub_strstr(pos, ")");
1415 }
1416
1417 if (pos2)
1418 {
1419 *pos2 = 0;
1420 }
1421
1422 disk = grub_disk_open(pos);
1423 if (disk)
1424 {
1425 grub_disk_read(disk, 0, 0x180, 16, guid);
1426 grub_disk_close(disk);
1427 }
1428 else
1429 {
1430 return 1;
1431 }
1432
1433 grub_free(device_name);
1434 return 0;
1435 }
1436
1437 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
1438 {
1439 eltorito_descriptor desc;
1440
1441 grub_memset(&desc, 0, sizeof(desc));
1442 grub_file_seek(file, 17 * 2048);
1443 grub_file_read(file, &desc, sizeof(desc));
1444
1445 if (desc.type != 0 || desc.version != 1)
1446 {
1447 return 0;
1448 }
1449
1450 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
1451 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
1452 {
1453 return 0;
1454 }
1455
1456 return desc.sector;
1457 }
1458
1459 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
1460 {
1461 int i;
1462 int x86count = 0;
1463 grub_uint8_t buf[512];
1464
1465 grub_file_seek(file, sector * 2048);
1466 grub_file_read(file, buf, sizeof(buf));
1467
1468 if (buf[0] == 0x01 && buf[1] == 0xEF)
1469 {
1470 debug("%s efi eltorito in Validation Entry\n", file->name);
1471 return 1;
1472 }
1473
1474 if (buf[0] == 0x01 && buf[1] == 0x00)
1475 {
1476 x86count++;
1477 }
1478
1479 for (i = 64; i < (int)sizeof(buf); i += 32)
1480 {
1481 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
1482 {
1483 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1484 return 1;
1485 }
1486
1487 if (buf[i] == 0x91 && buf[i + 1] == 0x00 && x86count == 1)
1488 {
1489 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1490 return 1;
1491 }
1492 }
1493
1494 debug("%s does not contain efi eltorito\n", file->name);
1495 return 0;
1496 }
1497
1498 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1499 {
1500 char *pos;
1501 const char *fs = NULL;
1502 const char *cdprompt = NULL;
1503 grub_uint32_t i;
1504 grub_uint8_t chksum = 0;
1505 grub_disk_t disk;
1506
1507 disk = file->device->disk;
1508 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1509
1510 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1511 param->vtoy_disk_part_id = disk->partition->number + 1;
1512 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
1513
1514 pos = grub_strstr(file->name, "/");
1515 if (!pos)
1516 {
1517 pos = file->name;
1518 }
1519
1520 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1521
1522 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1523
1524 param->vtoy_img_size = file->size;
1525
1526 param->vtoy_reserved[0] = g_ventoy_break_level;
1527 param->vtoy_reserved[1] = g_ventoy_debug_level;
1528
1529 param->vtoy_reserved[2] = g_ventoy_chain_type;
1530
1531 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1532 param->vtoy_reserved[4] = 0;
1533 if (g_ventoy_chain_type == 1) /* Windows */
1534 {
1535 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1536 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
1537 {
1538 param->vtoy_reserved[4] = 1;
1539 }
1540 }
1541
1542 fs = ventoy_get_env("ventoy_fs_probe");
1543 if (fs && grub_strcmp(fs, "udf") == 0)
1544 {
1545 param->vtoy_reserved[3] = 1;
1546 }
1547
1548 /* calculate checksum */
1549 for (i = 0; i < sizeof(ventoy_os_param); i++)
1550 {
1551 chksum += *((grub_uint8_t *)param + i);
1552 }
1553 param->chksum = (grub_uint8_t)(0x100 - chksum);
1554
1555 return;
1556 }
1557
1558 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1559 {
1560 grub_uint32_t i = 0;
1561 grub_uint64_t total = 0;
1562 ventoy_img_chunk *chunk = NULL;
1563
1564 for (i = 0; i < chunklist->cur_chunk; i++)
1565 {
1566 chunk = chunklist->chunk + i;
1567
1568 if (chunk->disk_start_sector <= start)
1569 {
1570 debug("%u disk start invalid %lu\n", i, (ulong)start);
1571 return 1;
1572 }
1573
1574 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
1575 }
1576
1577 if (total != ((file->size + 511) / 512))
1578 {
1579 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
1580 return 1;
1581 }
1582
1583 return 0;
1584 }
1585
1586 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1587 {
1588 int fs_type;
1589 grub_uint32_t i = 0;
1590 grub_uint32_t sector = 0;
1591 grub_uint32_t count = 0;
1592 grub_off_t size = 0;
1593 grub_off_t read = 0;
1594
1595 fs_type = ventoy_get_fs_type(file->fs->name);
1596 if (fs_type == ventoy_fs_exfat)
1597 {
1598 grub_fat_get_file_chunk(start, file, chunklist);
1599 }
1600 else if (fs_type == ventoy_fs_ext)
1601 {
1602 grub_ext_get_file_chunk(start, file, chunklist);
1603 }
1604 else
1605 {
1606 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
1607 file->read_hook_data = chunklist;
1608
1609 for (size = file->size; size > 0; size -= read)
1610 {
1611 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
1612 grub_file_read(file, NULL, read);
1613 }
1614
1615 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
1616 {
1617 chunklist->chunk[i].disk_start_sector += start;
1618 chunklist->chunk[i].disk_end_sector += start;
1619 }
1620
1621 if (ventoy_fs_udf == fs_type)
1622 {
1623 for (i = 0; i < chunklist->cur_chunk; i++)
1624 {
1625 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
1626 chunklist->chunk[i].img_start_sector = sector;
1627 chunklist->chunk[i].img_end_sector = sector + count - 1;
1628 sector += count;
1629 }
1630 }
1631 }
1632
1633 return 0;
1634 }
1635
1636 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1637 {
1638 int rc;
1639 grub_file_t file;
1640 grub_disk_addr_t start;
1641
1642 (void)ctxt;
1643 (void)argc;
1644
1645 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1646 if (!file)
1647 {
1648 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1649 }
1650
1651 if (g_img_chunk_list.chunk)
1652 {
1653 grub_free(g_img_chunk_list.chunk);
1654 }
1655
1656 /* get image chunk data */
1657 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1658 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1659 if (NULL == g_img_chunk_list.chunk)
1660 {
1661 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1662 }
1663
1664 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1665 g_img_chunk_list.cur_chunk = 0;
1666
1667 start = file->device->disk->partition->start;
1668
1669 ventoy_get_block_list(file, &g_img_chunk_list, start);
1670
1671 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
1672 grub_file_close(file);
1673
1674 if (rc)
1675 {
1676 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
1677 }
1678
1679 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1680 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1681 }
1682
1683 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1684 {
1685 int i = 0;
1686 int pos = 0;
1687 char *buf = NULL;
1688 char configfile[128];
1689 install_template *node = NULL;
1690
1691 (void)ctxt;
1692 (void)argc;
1693 (void)args;
1694
1695 debug("select auto installation argc:%d\n", argc);
1696
1697 if (argc < 1)
1698 {
1699 return 0;
1700 }
1701
1702 node = ventoy_plugin_find_install_template(args[0]);
1703 if (!node)
1704 {
1705 debug("Auto install template not found for %s\n", args[0]);
1706 return 0;
1707 }
1708
1709 if (node->autosel >= 0 && node->autosel <= node->templatenum)
1710 {
1711 node->cursel = node->autosel - 1;
1712 debug("Auto install template auto select %d\n", node->autosel);
1713 return 0;
1714 }
1715
1716 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
1717 if (!buf)
1718 {
1719 return 0;
1720 }
1721
1722 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
1723 " echo %s\n}\n", "123");
1724
1725 for (i = 0; i < node->templatenum; i++)
1726 {
1727 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
1728 " echo 123\n}\n",
1729 node->templatepath[i].path);
1730 }
1731
1732 g_ventoy_menu_esc = 1;
1733 g_ventoy_suppress_esc = 1;
1734
1735 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
1736 grub_script_execute_sourcecode(configfile);
1737
1738 g_ventoy_menu_esc = 0;
1739 g_ventoy_suppress_esc = 0;
1740
1741 grub_free(buf);
1742
1743 node->cursel = g_ventoy_last_entry - 1;
1744
1745 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1746 }
1747
1748 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
1749 {
1750 int i = 0;
1751 int pos = 0;
1752 char *buf = NULL;
1753 char configfile[128];
1754 persistence_config *node;
1755
1756 (void)ctxt;
1757 (void)argc;
1758 (void)args;
1759
1760 debug("select persistence argc:%d\n", argc);
1761
1762 if (argc < 1)
1763 {
1764 return 0;
1765 }
1766
1767 node = ventoy_plugin_find_persistent(args[0]);
1768 if (!node)
1769 {
1770 debug("Persistence image not found for %s\n", args[0]);
1771 return 0;
1772 }
1773
1774 if (node->autosel >= 0 && node->autosel <= node->backendnum)
1775 {
1776 node->cursel = node->autosel - 1;
1777 debug("Persistence image auto select %d\n", node->autosel);
1778 return 0;
1779 }
1780
1781 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
1782 if (!buf)
1783 {
1784 return 0;
1785 }
1786
1787 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
1788 " echo %s\n}\n", "123");
1789
1790 for (i = 0; i < node->backendnum; i++)
1791 {
1792 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
1793 " echo 123\n}\n",
1794 node->backendpath[i].path);
1795
1796 }
1797
1798 g_ventoy_menu_esc = 1;
1799 g_ventoy_suppress_esc = 1;
1800
1801 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
1802 grub_script_execute_sourcecode(configfile);
1803
1804 g_ventoy_menu_esc = 0;
1805 g_ventoy_suppress_esc = 0;
1806
1807 grub_free(buf);
1808
1809 node->cursel = g_ventoy_last_entry - 1;
1810
1811 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1812 }
1813
1814 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1815 {
1816 grub_uint32_t i;
1817 ventoy_img_chunk *cur;
1818
1819 (void)ctxt;
1820 (void)argc;
1821 (void)args;
1822
1823 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
1824 {
1825 cur = g_img_chunk_list.chunk + i;
1826 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1827 cur->img_start_sector, cur->img_end_sector,
1828 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
1829 );
1830 }
1831
1832 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1833 }
1834
1835 #ifdef GRUB_MACHINE_EFI
1836 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1837 {
1838 (void)ctxt;
1839 (void)argc;
1840 (void)args;
1841 return 0;
1842 }
1843 #else
1844 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1845 {
1846 int rc = 0;
1847 ulong chain_len = 0;
1848 char *chain_data = NULL;
1849 char *relocator_addr = NULL;
1850 grub_relocator_chunk_t ch;
1851 struct grub_relocator *relocator = NULL;
1852 char envbuf[64] = { 0 };
1853
1854 (void)ctxt;
1855 (void)argc;
1856 (void)args;
1857
1858 if (argc != 2)
1859 {
1860 return 1;
1861 }
1862
1863 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
1864 chain_len = grub_strtoul(args[1], NULL, 10);
1865
1866 relocator = grub_relocator_new ();
1867 if (!relocator)
1868 {
1869 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
1870 return 1;
1871 }
1872
1873 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
1874 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1875 chain_len);
1876 if (rc)
1877 {
1878 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
1879 grub_relocator_unload (relocator);
1880 return 1;
1881 }
1882
1883 relocator_addr = get_virtual_current_address(ch);
1884
1885 grub_memcpy(relocator_addr, chain_data, chain_len);
1886
1887 grub_relocator_unload (relocator);
1888
1889 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
1890 grub_env_set("vtoy_chain_relocator_addr", envbuf);
1891
1892 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1893 }
1894 #endif
1895
1896 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
1897 {
1898 grub_uint32_t i;
1899 grub_file_t file;
1900 ventoy_img_chunk_list chunklist;
1901
1902 (void)ctxt;
1903 (void)argc;
1904
1905 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1906 if (!file)
1907 {
1908 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1909 }
1910
1911 /* get image chunk data */
1912 grub_memset(&chunklist, 0, sizeof(chunklist));
1913 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1914 if (NULL == chunklist.chunk)
1915 {
1916 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1917 }
1918
1919 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
1920 chunklist.cur_chunk = 0;
1921
1922 ventoy_get_block_list(file, &chunklist, 0);
1923
1924 if (0 != ventoy_check_block_list(file, &chunklist, 0))
1925 {
1926 grub_printf("########## UNSUPPORTED ###############\n");
1927 }
1928
1929 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
1930
1931 for (i = 0; i < chunklist.cur_chunk; i++)
1932 {
1933 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
1934 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
1935 }
1936
1937 grub_printf("\n==================================\n");
1938
1939 for (i = 0; i < chunklist.cur_chunk; i++)
1940 {
1941 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
1942 (ulonglong)chunklist.chunk[i].img_start_sector,
1943 (ulonglong)chunklist.chunk[i].img_end_sector,
1944 (ulonglong)chunklist.chunk[i].disk_start_sector,
1945 (ulonglong)chunklist.chunk[i].disk_end_sector
1946 );
1947 }
1948
1949 grub_free(chunklist.chunk);
1950 grub_file_close(file);
1951
1952 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1953 }
1954
1955 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
1956 {
1957 int i;
1958 ventoy_grub_param_file_replace *replace = NULL;
1959
1960 (void)ctxt;
1961 (void)argc;
1962 (void)args;
1963
1964 if (argc >= 2)
1965 {
1966 replace = &(g_grub_param->file_replace);
1967 replace->magic = GRUB_FILE_REPLACE_MAGIC;
1968
1969 replace->old_name_cnt = 0;
1970 for (i = 0; i < 4 && i + 1 < argc; i++)
1971 {
1972 replace->old_name_cnt++;
1973 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
1974 }
1975
1976 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
1977 }
1978
1979 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1980 }
1981
1982 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1983 {
1984 (void)ctxt;
1985 (void)argc;
1986 (void)args;
1987
1988 if (argc == 0)
1989 {
1990 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
1991 grub_printf("%s", g_list_script_buf);
1992 }
1993 else
1994 {
1995 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
1996 grub_printf("%s", g_tree_script_buf);
1997 }
1998
1999 return 0;
2000 }
2001
2002 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
2003 {
2004 img_info *cur = g_ventoy_img_list;
2005
2006 (void)ctxt;
2007 (void)argc;
2008 (void)args;
2009
2010 while (cur)
2011 {
2012 grub_printf("path:<%s> id=%d\n", cur->path, cur->id);
2013 grub_printf("name:<%s>\n\n", cur->name);
2014 cur = cur->next;
2015 }
2016
2017 return 0;
2018 }
2019
2020 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
2021 {
2022 (void)ctxt;
2023 (void)argc;
2024 (void)args;
2025
2026 ventoy_plugin_dump_auto_install();
2027
2028 return 0;
2029 }
2030
2031 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
2032 {
2033 (void)ctxt;
2034 (void)argc;
2035 (void)args;
2036
2037 ventoy_plugin_dump_persistence();
2038
2039 return 0;
2040 }
2041
2042 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
2043 {
2044 (void)ctxt;
2045 (void)argc;
2046 (void)args;
2047
2048 if (argc != 1)
2049 {
2050 return 1;
2051 }
2052
2053 if (args[0][0] == '0')
2054 {
2055 return g_ventoy_memdisk_mode ? 0 : 1;
2056 }
2057 else if (args[0][0] == '1')
2058 {
2059 return g_ventoy_iso_raw ? 0 : 1;
2060 }
2061 else if (args[0][0] == '2')
2062 {
2063 return g_ventoy_iso_uefi_drv ? 0 : 1;
2064 }
2065
2066 return 1;
2067 }
2068
2069 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
2070 {
2071 static int configfile_mode = 0;
2072 char memfile[128] = {0};
2073
2074 (void)ctxt;
2075 (void)argc;
2076 (void)args;
2077
2078 /*
2079 * args[0]: 0:normal 1:configfile
2080 * args[1]: 0:list_buf 1:tree_buf
2081 */
2082
2083 if (argc != 2)
2084 {
2085 debug("Invalid argc %d\n", argc);
2086 return 0;
2087 }
2088
2089 if (args[0][0] == '0')
2090 {
2091 if (args[1][0] == '0')
2092 {
2093 grub_script_execute_sourcecode(g_list_script_buf);
2094 }
2095 else
2096 {
2097 grub_script_execute_sourcecode(g_tree_script_buf);
2098 }
2099 }
2100 else
2101 {
2102 if (configfile_mode)
2103 {
2104 debug("Now already in F3 mode %d\n", configfile_mode);
2105 return 0;
2106 }
2107
2108 if (args[1][0] == '0')
2109 {
2110 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2111 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
2112 }
2113 else
2114 {
2115 g_ventoy_last_entry = -1;
2116 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
2117 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
2118 }
2119
2120 configfile_mode = 1;
2121 grub_script_execute_sourcecode(memfile);
2122 configfile_mode = 0;
2123 }
2124
2125 return 0;
2126 }
2127
2128 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
2129 {
2130 grub_file_t file;
2131
2132 (void)ctxt;
2133
2134 if (argc != 1)
2135 {
2136 return 1;
2137 }
2138
2139 g_ventoy_case_insensitive = 1;
2140 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
2141 g_ventoy_case_insensitive = 0;
2142
2143 grub_errno = 0;
2144
2145 if (file)
2146 {
2147 grub_file_close(file);
2148 return 0;
2149 }
2150 return 1;
2151 }
2152
2153 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
2154 {
2155 int id = 0;
2156 int find = 0;
2157 grub_disk_t disk;
2158 const char *isopath = NULL;
2159 char hdname[32];
2160 ventoy_mbr_head mbr;
2161
2162 (void)ctxt;
2163 (void)argc;
2164
2165 if (argc != 1)
2166 {
2167 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
2168 }
2169
2170 isopath = grub_env_get("vtoy_iso_part");
2171 if (!isopath)
2172 {
2173 debug("isopath is null %p\n", isopath);
2174 return 0;
2175 }
2176
2177 debug("isopath is %s\n", isopath);
2178
2179 for (id = 0; id < 30 && (find == 0); id++)
2180 {
2181 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
2182 if (grub_strstr(isopath, hdname))
2183 {
2184 debug("skip %s ...\n", hdname);
2185 continue;
2186 }
2187
2188 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
2189
2190 disk = grub_disk_open(hdname);
2191 if (!disk)
2192 {
2193 debug("%s not exist\n", hdname);
2194 break;
2195 }
2196
2197 grub_memset(&mbr, 0, sizeof(mbr));
2198 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
2199 {
2200 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
2201 {
2202 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
2203 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
2204 {
2205
2206 grub_env_set(args[0], hdname);
2207 find = 1;
2208 }
2209 }
2210 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
2211 }
2212 else
2213 {
2214 debug("read %s failed\n", hdname);
2215 }
2216
2217 grub_disk_close(disk);
2218 }
2219
2220 return 0;
2221 }
2222
2223 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
2224 {
2225 grub_uint64_t size = 0;
2226 grub_file_t file;
2227 va_list ap;
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, VENTOY_FILE_TYPE);
2235 if (!file)
2236 {
2237 debug("grub_file_open failed <%s>\n", fullpath);
2238 grub_errno = 0;
2239 return 0;
2240 }
2241
2242 size = file->size;
2243 grub_file_close(file);
2244 return size;
2245 }
2246
2247 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
2248 {
2249 va_list ap;
2250 grub_file_t file;
2251 char fullpath[256] = {0};
2252
2253 va_start (ap, fmt);
2254 grub_vsnprintf(fullpath, 255, fmt, ap);
2255 va_end (ap);
2256
2257 file = grub_file_open(fullpath, type);
2258 if (!file)
2259 {
2260 debug("grub_file_open failed <%s>\n", fullpath);
2261 grub_errno = 0;
2262 }
2263
2264 return file;
2265 }
2266
2267 int ventoy_is_file_exist(const char *fmt, ...)
2268 {
2269 va_list ap;
2270 int len;
2271 char *pos = NULL;
2272 char buf[256] = {0};
2273
2274 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
2275 pos = buf + 5;
2276
2277 va_start (ap, fmt);
2278 len = grub_vsnprintf(pos, 255, fmt, ap);
2279 va_end (ap);
2280
2281 grub_strncpy(pos + len, " ]", 2);
2282
2283 debug("script exec %s\n", buf);
2284
2285 if (0 == grub_script_execute_sourcecode(buf))
2286 {
2287 return 1;
2288 }
2289
2290 return 0;
2291 }
2292
2293 int ventoy_is_dir_exist(const char *fmt, ...)
2294 {
2295 va_list ap;
2296 int len;
2297 char *pos = NULL;
2298 char buf[256] = {0};
2299
2300 grub_snprintf(buf, sizeof(buf), "%s", "[ -d ");
2301 pos = buf + 5;
2302
2303 va_start (ap, fmt);
2304 len = grub_vsnprintf(pos, 255, fmt, ap);
2305 va_end (ap);
2306
2307 grub_strncpy(pos + len, " ]", 2);
2308
2309 debug("script exec %s\n", buf);
2310
2311 if (0 == grub_script_execute_sourcecode(buf))
2312 {
2313 return 1;
2314 }
2315
2316 return 0;
2317 }
2318
2319 static int ventoy_env_init(void)
2320 {
2321 char buf[64];
2322
2323 grub_env_set("vtdebug_flag", "");
2324
2325 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2326 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
2327
2328 ventoy_filt_register(0, ventoy_wrapper_open);
2329
2330 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
2331 if (g_grub_param)
2332 {
2333 g_grub_param->grub_env_get = grub_env_get;
2334 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
2335 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
2336 grub_env_set("env_param", buf);
2337 }
2338
2339 return 0;
2340 }
2341
2342 static cmd_para ventoy_cmds[] =
2343 {
2344 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
2345 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2346 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
2347 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
2348 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
2349 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
2350 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
2351 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
2352 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
2353 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
2354 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
2355 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
2356 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
2357 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
2358 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
2359 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
2360 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
2361 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
2362 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
2363 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
2364 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
2365 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
2366 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
2367 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
2368
2369 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
2370 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
2371 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
2372 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
2373
2374 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2375 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
2376 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
2377 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
2378 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
2379 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
2380 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
2381 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
2382 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
2383 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
2384
2385 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
2386 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
2387 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
2388 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
2389 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
2390 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
2391 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
2392
2393 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
2394 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
2395 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
2396 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
2397
2398
2399 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
2400 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
2401
2402 };
2403
2404
2405
2406 GRUB_MOD_INIT(ventoy)
2407 {
2408 grub_uint32_t i;
2409 cmd_para *cur = NULL;
2410
2411 ventoy_env_init();
2412
2413 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2414 {
2415 cur = ventoy_cmds + i;
2416 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
2417 cur->summary, cur->description, cur->parser);
2418 }
2419 }
2420
2421 GRUB_MOD_FINI(ventoy)
2422 {
2423 grub_uint32_t i;
2424
2425 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
2426 {
2427 grub_unregister_extcmd(ventoy_cmds[i].cmd);
2428 }
2429 }
2430