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