]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
1. change some directory structure for the build script
[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 #ifdef GRUB_MACHINE_EFI
37 #include <grub/efi/efi.h>
38 #endif
39 #include <grub/time.h>
40 #include <grub/relocator.h>
41 #include <grub/ventoy.h>
42 #include "ventoy_def.h"
43
44 GRUB_MOD_LICENSE ("GPLv3+");
45
46 int g_ventoy_debug = 0;
47 static int g_efi_os = 0xFF;
48 initrd_info *g_initrd_img_list = NULL;
49 initrd_info *g_initrd_img_tail = NULL;
50 int g_initrd_img_count = 0;
51 int g_valid_initrd_count = 0;
52 int g_filt_dot_underscore_file = 0;
53 static grub_file_t g_old_file;
54
55 char g_img_swap_tmp_buf[1024];
56 img_info g_img_swap_tmp;
57 img_info *g_ventoy_img_list = NULL;
58 int g_ventoy_img_count = 0;
59
60 grub_device_t g_enum_dev = NULL;
61 grub_fs_t g_enum_fs = NULL;
62 img_iterator_node g_img_iterator_head;
63 img_iterator_node *g_img_iterator_tail = NULL;
64
65 grub_uint8_t g_ventoy_break_level = 0;
66 grub_uint8_t g_ventoy_debug_level = 0;
67 grub_uint8_t *g_ventoy_cpio_buf = NULL;
68 grub_uint32_t g_ventoy_cpio_size = 0;
69 cpio_newc_header *g_ventoy_initrd_head = NULL;
70 grub_uint8_t *g_ventoy_runtime_buf = NULL;
71
72 ventoy_grub_param *g_grub_param = NULL;
73
74 ventoy_guid g_ventoy_guid = VENTOY_GUID;
75
76 ventoy_img_chunk_list g_img_chunk_list;
77
78 static char *g_tree_script_buf = NULL;
79 static int g_tree_script_pos = 0;
80
81 static char *g_list_script_buf = NULL;
82 static int g_list_script_pos = 0;
83
84
85 void ventoy_debug(const char *fmt, ...)
86 {
87 va_list args;
88
89 va_start (args, fmt);
90 grub_vprintf (fmt, args);
91 va_end (args);
92 }
93
94 int ventoy_is_efi_os(void)
95 {
96 if (g_efi_os > 1)
97 {
98 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
99 }
100
101 return g_efi_os;
102 }
103
104 static int ventoy_get_fs_type(const char *fs)
105 {
106 if (NULL == fs)
107 {
108 return ventoy_fs_max;
109 }
110 else if (grub_strncmp(fs, "exfat", 5) == 0)
111 {
112 return ventoy_fs_exfat;
113 }
114 else if (grub_strncmp(fs, "ntfs", 4) == 0)
115 {
116 return ventoy_fs_ntfs;
117 }
118 else if (grub_strncmp(fs, "ext", 3) == 0)
119 {
120 return ventoy_fs_ext;
121 }
122 else if (grub_strncmp(fs, "xfs", 3) == 0)
123 {
124 return ventoy_fs_xfs;
125 }
126 else if (grub_strncmp(fs, "udf", 3) == 0)
127 {
128 return ventoy_fs_udf;
129 }
130
131 return ventoy_fs_max;
132 }
133
134 static int ventoy_string_check(const char *str, grub_char_check_func check)
135 {
136 if (!str)
137 {
138 return 0;
139 }
140
141 for ( ; *str; str++)
142 {
143 if (!check(*str))
144 {
145 return 0;
146 }
147 }
148
149 return 1;
150 }
151
152
153 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
154 {
155 grub_memcpy(buf, (char *)file->data + file->offset, len);
156 return len;
157 }
158
159 static grub_err_t ventoy_fs_close(grub_file_t file)
160 {
161 grub_file_close(g_old_file);
162 grub_free(file->data);
163
164 file->device = 0;
165 file->name = 0;
166
167 return 0;
168 }
169
170 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
171 {
172 int len;
173 grub_file_t file;
174 static struct grub_fs vtoy_fs =
175 {
176 .name = "vtoy",
177 .fs_dir = 0,
178 .fs_open = 0,
179 .fs_read = ventoy_fs_read,
180 .fs_close = ventoy_fs_close,
181 .fs_label = 0,
182 .next = 0
183 };
184
185 if (type != 52)
186 {
187 return rawFile;
188 }
189
190 file = (grub_file_t)grub_zalloc(sizeof (*file));
191 if (!file)
192 {
193 return 0;
194 }
195
196 file->data = grub_malloc(rawFile->size + 4096);
197 if (!file->data)
198 {
199 return 0;
200 }
201
202 grub_file_read(rawFile, file->data, rawFile->size);
203 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
204
205 g_old_file = rawFile;
206
207 file->size = rawFile->size + len;
208 file->device = rawFile->device;
209 file->fs = &vtoy_fs;
210 file->not_easily_seekable = 1;
211
212 return file;
213 }
214
215 static int ventoy_check_decimal_var(const char *name, long *value)
216 {
217 const char *value_str = NULL;
218
219 value_str = grub_env_get(name);
220 if (NULL == value_str)
221 {
222 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
223 }
224
225 if (!ventoy_is_decimal(value_str))
226 {
227 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
228 }
229
230 *value = grub_strtol(value_str, NULL, 10);
231
232 return GRUB_ERR_NONE;
233 }
234
235 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
236 {
237 if (argc != 1)
238 {
239 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
240 }
241
242 if (0 == grub_strcmp(args[0], "on"))
243 {
244 g_ventoy_debug = 1;
245 grub_env_set("vtdebug_flag", "debug");
246 }
247 else
248 {
249 g_ventoy_debug = 0;
250 grub_env_set("vtdebug_flag", "");
251 }
252
253 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
254 }
255
256 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
257 {
258 (void)ctxt;
259
260 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
261 {
262 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
263 grub_printf(" level:\r\n");
264 grub_printf(" 01/11: busybox / (+cat log)\r\n");
265 grub_printf(" 02/12: initrd / (+cat log)\r\n");
266 grub_printf(" 03/13: hook / (+cat log)\r\n");
267 grub_printf("\r\n");
268 grub_printf(" debug:\r\n");
269 grub_printf(" 0: debug is on\r\n");
270 grub_printf(" 1: debug is off\r\n");
271 grub_printf("\r\n");
272 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
273 }
274
275 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
276
277 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
278 {
279 g_ventoy_debug_level = 1;
280 }
281
282 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
283 }
284
285 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
286 {
287 long value_long = 0;
288 char buf[32];
289
290 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
291 {
292 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
293 }
294
295 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
296 {
297 return grub_errno;
298 }
299
300 value_long += grub_strtol(args[1], NULL, 10);
301
302 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
303 grub_env_set(args[0], buf);
304
305 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
306 }
307
308 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
309 {
310 int rc = 1;
311 char buf[32];
312 grub_file_t file;
313
314 (void)ctxt;
315 (void)argc;
316 (void)args;
317
318 if (argc != 2)
319 {
320 return rc;
321 }
322
323 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
324 if (file == NULL)
325 {
326 debug("failed to open file <%s> for udf check\n", args[0]);
327 return 1;
328 }
329
330 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
331
332 grub_env_set(args[1], buf);
333
334 grub_file_close(file);
335 rc = 0;
336
337 return rc;
338 }
339
340 static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
341 {
342 int rc = 1;
343 char name[32];
344 char value[32];
345 char *buf = NULL;
346 grub_file_t file;
347
348 (void)ctxt;
349 (void)argc;
350 (void)args;
351
352 if (argc != 2)
353 {
354 return rc;
355 }
356
357 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
358 if (file == NULL)
359 {
360 debug("failed to open file <%s> for udf check\n", args[0]);
361 return 1;
362 }
363
364 #ifdef GRUB_MACHINE_EFI
365 buf = (char *)grub_efi_allocate_iso_buf(file->size);
366 #else
367 buf = (char *)grub_malloc(file->size);
368 #endif
369
370 grub_file_read(file, buf, file->size);
371
372 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
373 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
374 grub_env_set(name, value);
375
376 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
377 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
378 grub_env_set(name, value);
379
380 grub_file_close(file);
381 rc = 0;
382
383 return rc;
384 }
385
386 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
387 {
388 int i;
389 int rc = 1;
390 grub_file_t file;
391 grub_uint8_t buf[32];
392
393 (void)ctxt;
394 (void)argc;
395 (void)args;
396
397 if (argc != 1)
398 {
399 return rc;
400 }
401
402 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
403 if (file == NULL)
404 {
405 debug("failed to open file <%s> for udf check\n", args[0]);
406 return 1;
407 }
408
409 for (i = 16; i < 32; i++)
410 {
411 grub_file_seek(file, i * 2048);
412 grub_file_read(file, buf, sizeof(buf));
413 if (buf[0] == 255)
414 {
415 break;
416 }
417 }
418
419 i++;
420 grub_file_seek(file, i * 2048);
421 grub_file_read(file, buf, sizeof(buf));
422
423 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
424 {
425 i++;
426 grub_file_seek(file, i * 2048);
427 grub_file_read(file, buf, sizeof(buf));
428
429 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
430 grub_memcmp(buf + 1, "NSR03", 5) == 0)
431 {
432 rc = 0;
433 }
434 }
435
436 grub_file_close(file);
437
438 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
439
440 return rc;
441 }
442
443 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
444 {
445 long value_long1 = 0;
446 long value_long2 = 0;
447
448 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
449 {
450 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
451 }
452
453 value_long1 = grub_strtol(args[0], NULL, 10);
454 value_long2 = grub_strtol(args[2], NULL, 10);
455
456 if (0 == grub_strcmp(args[1], "eq"))
457 {
458 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
459 }
460 else if (0 == grub_strcmp(args[1], "ne"))
461 {
462 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
463 }
464 else if (0 == grub_strcmp(args[1], "gt"))
465 {
466 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
467 }
468 else if (0 == grub_strcmp(args[1], "lt"))
469 {
470 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
471 }
472 else if (0 == grub_strcmp(args[1], "ge"))
473 {
474 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
475 }
476 else if (0 == grub_strcmp(args[1], "le"))
477 {
478 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
479 }
480 else
481 {
482 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
483 }
484
485 return grub_errno;
486 }
487
488 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
489 {
490 char *pos = NULL;
491 char buf[128] = {0};
492
493 if (argc != 2)
494 {
495 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
496 }
497
498 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
499 pos = grub_strstr(buf, ",");
500 if (pos)
501 {
502 *pos = 0;
503 }
504
505 grub_env_set(args[1], buf);
506
507 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
508 }
509
510 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
511 {
512 int i;
513 char buf[256];
514 grub_disk_t disk;
515 char *pos = NULL;
516 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
517
518 (void)ctxt;
519
520 if (argc != 1)
521 {
522 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
523 }
524
525 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
526 {
527 grub_snprintf(buf, sizeof(buf) - 1, "[ -e %s/%s ]", args[0], files[i]);
528 if (0 == grub_script_execute_sourcecode(buf))
529 {
530 debug("file %s exist, ventoy_compatible YES\n", buf);
531 grub_env_set("ventoy_compatible", "YES");
532 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
533 }
534 else
535 {
536 debug("file %s NOT exist\n", buf);
537 }
538 }
539
540 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
541 pos = grub_strstr(buf, ")");
542 if (pos)
543 {
544 *pos = 0;
545 }
546
547 disk = grub_disk_open(buf);
548 if (disk)
549 {
550 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
551 grub_disk_close(disk);
552
553 g_img_swap_tmp_buf[703] = 0;
554 for (i = 319; i < 703; i++)
555 {
556 if (g_img_swap_tmp_buf[i] == 'V' &&
557 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
558 {
559 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
560 grub_env_set("ventoy_compatible", "YES");
561 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
562 }
563 }
564 }
565 else
566 {
567 debug("failed to open disk <%s>\n", buf);
568 }
569
570 grub_env_set("ventoy_compatible", "NO");
571 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
572 }
573
574 int ventoy_cmp_img(img_info *img1, img_info *img2)
575 {
576 char *s1, *s2;
577 int c1 = 0;
578 int c2 = 0;
579
580 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
581 {
582 c1 = *s1;
583 c2 = *s2;
584
585 if (grub_islower(c1))
586 {
587 c1 = c1 - 'a' + 'A';
588 }
589
590 if (grub_islower(c2))
591 {
592 c2 = c2 - 'a' + 'A';
593 }
594
595 if (c1 != c2)
596 {
597 break;
598 }
599 }
600
601 return (c1 - c2);
602 }
603
604 void ventoy_swap_img(img_info *img1, img_info *img2)
605 {
606 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
607
608 grub_memcpy(img1, img2, sizeof(img_info));
609 img1->next = g_img_swap_tmp.next;
610 img1->prev = g_img_swap_tmp.prev;
611
612 g_img_swap_tmp.next = img2->next;
613 g_img_swap_tmp.prev = img2->prev;
614 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
615 }
616
617 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
618 {
619 grub_size_t i;
620
621 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
622 {
623 return 0;
624 }
625
626 for (i = 0; i < namelen; i++)
627 {
628 if (filename[i] == ' ' || filename[i] == '\t')
629 {
630 return 0;
631 }
632
633 if ((grub_uint8_t)(filename[i]) >= 127)
634 {
635 return 0;
636 }
637 }
638
639 return 1;
640 }
641
642 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
643 {
644 if (0 == info->dir)
645 {
646 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
647 {
648 *((int *)data) = 1;
649 return 0;
650 }
651 }
652
653 return 0;
654 }
655
656 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
657 {
658 int ignore = 0;
659 grub_size_t len;
660 img_info *img;
661 img_info *tail;
662 img_iterator_node *tmp;
663 img_iterator_node *new_node;
664 img_iterator_node *node = (img_iterator_node *)data;
665
666 len = grub_strlen(filename);
667
668 if (info->dir)
669 {
670 if ((len == 1 && filename[0] == '.') ||
671 (len == 2 && filename[0] == '.' && filename[1] == '.'))
672 {
673 return 0;
674 }
675
676 if (!ventoy_img_name_valid(filename, len))
677 {
678 return 0;
679 }
680
681 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
682 {
683 return 0;
684 }
685
686 new_node = grub_zalloc(sizeof(img_iterator_node));
687 if (new_node)
688 {
689 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
690
691 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
692 if (ignore)
693 {
694 debug("Directory %s ignored...\n", new_node->dir);
695 grub_free(new_node);
696 return 0;
697 }
698
699 new_node->tail = node->tail;
700
701 new_node->parent = node;
702 if (!node->firstchild)
703 {
704 node->firstchild = new_node;
705 }
706
707 if (g_img_iterator_tail)
708 {
709 g_img_iterator_tail->next = new_node;
710 g_img_iterator_tail = new_node;
711 }
712 else
713 {
714 g_img_iterator_head.next = new_node;
715 g_img_iterator_tail = new_node;
716 }
717 }
718 }
719 else
720 {
721 debug("Find a file %s\n", filename);
722
723 if ((len > 4) && (0 == grub_strcasecmp(filename + len - 4, ".iso")))
724 {
725 if (!ventoy_img_name_valid(filename, len))
726 {
727 return 0;
728 }
729
730 img = grub_zalloc(sizeof(img_info));
731 if (img)
732 {
733 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
734 grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, filename);
735
736 if (g_ventoy_img_list)
737 {
738 tail = *(node->tail);
739 img->prev = tail;
740 tail->next = img;
741 }
742 else
743 {
744 g_ventoy_img_list = img;
745 }
746
747 img->size = info->size;
748 img->id = g_ventoy_img_count;
749 img->parent = node;
750 if (node && NULL == node->firstiso)
751 {
752 node->firstiso = img;
753 }
754
755 node->isocnt++;
756 tmp = node->parent;
757 while (tmp)
758 {
759 tmp->isocnt++;
760 tmp = tmp->parent;
761 }
762
763 *((img_info **)(node->tail)) = img;
764 g_ventoy_img_count++;
765
766 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
767 }
768 }
769 }
770
771 return 0;
772 }
773
774 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
775 {
776 int len = GRUB_UINT_MAX;
777 const char *value = NULL;
778 char name[32] = {0};
779 char plat[32] = {0};
780 char guidstr[32] = {0};
781 ventoy_guid guid = VENTOY_GUID;
782 const char *fmt1 = NULL;
783 const char *fmt2 = NULL;
784 const char *fmt3 = NULL;
785 grub_uint32_t *puint = (grub_uint32_t *)name;
786 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
787 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
788 const char fmtcode[]={
789 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
790 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
791 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
792 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
793 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
794 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
795 };
796
797 grub_memset(name, 0, sizeof(name));
798 puint[0] = grub_swap_bytes32(0x56454e54);
799 puint[3] = grub_swap_bytes32(0x4f4e0000);
800 puint[2] = grub_swap_bytes32(0x45525349);
801 puint[1] = grub_swap_bytes32(0x4f595f56);
802 value = ventoy_get_env(name);
803
804 grub_memset(name, 0, sizeof(name));
805 puint[1] = grub_swap_bytes32(0x5f544f50);
806 puint[0] = grub_swap_bytes32(0x56544c45);
807 fmt1 = ventoy_get_env(name);
808 if (!fmt1)
809 {
810 fmt1 = fmtdata;
811 }
812
813 grub_memset(name, 0, sizeof(name));
814 puint[1] = grub_swap_bytes32(0x5f4c4654);
815 puint[0] = grub_swap_bytes32(0x56544c45);
816 fmt2 = ventoy_get_env(name);
817
818 grub_memset(name, 0, sizeof(name));
819 puint[1] = grub_swap_bytes32(0x5f434c52);
820 puint[0] = grub_swap_bytes32(0x56544c45);
821 fmt3 = ventoy_get_env(name);
822
823 grub_memcpy(guidstr, &guid, sizeof(guid));
824
825 #if defined (GRUB_MACHINE_EFI)
826 puint2[0] = grub_swap_bytes32(0x55454649);
827 #else
828 puint2[0] = grub_swap_bytes32(0x42494f53);
829 #endif
830
831 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
832 #pragma GCC diagnostic push
833 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
834 len = grub_snprintf(buffer, buflen, fmtcode,
835 fmt1 ? fmt1 : fmtdata,
836 fmt2 ? fmt2 : fmtdata + 4,
837 value ? value : "", plat, guidstr,
838 fmt3 ? fmt3 : fmtdata + 6);
839 #pragma GCC diagnostic pop
840
841 grub_memset(name, 0, sizeof(name));
842 puint[0] = grub_swap_bytes32(0x76746f79);
843 puint[2] = grub_swap_bytes32(0x656e7365);
844 puint[1] = grub_swap_bytes32(0x5f6c6963);
845 ventoy_set_env(name, guidstr);
846
847 return len;
848 }
849
850 static img_info * ventoy_get_min_iso(img_iterator_node *node)
851 {
852 img_info *minimg = NULL;
853 img_info *img = (img_info *)(node->firstiso);
854
855 while (img && (img_iterator_node *)(img->parent) == node)
856 {
857 if (img->select == 0 && (NULL == minimg || grub_strcmp(img->name, minimg->name) < 0))
858 {
859 minimg = img;
860 }
861 img = img->next;
862 }
863
864 if (minimg)
865 {
866 minimg->select = 1;
867 }
868
869 return minimg;
870 }
871
872 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
873 {
874 img_iterator_node *Minchild = NULL;
875 img_iterator_node *child = node->firstchild;
876
877 while (child && child->parent == node)
878 {
879 if (child->select == 0 && (NULL == Minchild || grub_strcmp(child->dir, Minchild->dir) < 0))
880 {
881 Minchild = child;
882 }
883 child = child->next;
884 }
885
886 if (Minchild)
887 {
888 Minchild->select = 1;
889 }
890
891 return Minchild;
892 }
893
894 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
895 {
896 int offset = 1;
897 img_info *img;
898 img_iterator_node *child = NULL;
899
900 if (node->isocnt == 0 || node->done == 1)
901 {
902 return 0;
903 }
904
905 if (node->parent && node->parent->dirlen < node->dirlen)
906 {
907 offset = node->parent->dirlen;
908 }
909
910 if (node != &g_img_iterator_head)
911 {
912 node->dir[node->dirlen - 1] = 0;
913 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
914 "submenu \"%-10s [%s]\" {\n", "DIR", node->dir + offset);
915 }
916
917 while ((child = ventoy_get_min_child(node)) != NULL)
918 {
919 ventoy_dynamic_tree_menu(child);
920 }
921
922 while ((img = ventoy_get_min_iso(node)) != NULL)
923 {
924 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
925 "menuentry \"%-10s %s\" --id=\"VID_%d\" {\n"
926 " common_menuentry \n"
927 "}\n",
928 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->name, img->id);
929 }
930
931 if (node != &g_img_iterator_head)
932 {
933 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, "}\n");
934 }
935
936 node->done = 1;
937 return 0;
938 }
939
940 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
941 {
942 grub_fs_t fs;
943 grub_device_t dev = NULL;
944 img_info *cur = NULL;
945 img_info *tail = NULL;
946 const char *strdata = NULL;
947 char *device_name = NULL;
948 char buf[32];
949 img_iterator_node *node = NULL;
950 img_iterator_node *tmp = NULL;
951
952 (void)ctxt;
953
954 if (argc != 2)
955 {
956 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
957 }
958
959 if (g_ventoy_img_list || g_ventoy_img_count)
960 {
961 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
962 }
963
964 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
965 if (strdata && strdata[0] == '1' && strdata[1] == 0)
966 {
967 g_filt_dot_underscore_file = 1;
968 }
969
970 device_name = grub_file_get_device_name(args[0]);
971 if (!device_name)
972 {
973 goto fail;
974 }
975
976 g_enum_dev = dev = grub_device_open(device_name);
977 if (!dev)
978 {
979 goto fail;
980 }
981
982 g_enum_fs = fs = grub_fs_probe(dev);
983 if (!fs)
984 {
985 goto fail;
986 }
987
988 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
989 {
990 debug("unsupported fs:<%s>\n", fs->name);
991 goto fail;
992 }
993
994 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
995
996 g_img_iterator_head.dirlen = 1;
997 g_img_iterator_head.tail = &tail;
998 grub_strcpy(g_img_iterator_head.dir, "/");
999
1000 for (node = &g_img_iterator_head; node; node = node->next)
1001 {
1002 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
1003 }
1004
1005 for (node = &g_img_iterator_head; node; node = node->next)
1006 {
1007 ventoy_dynamic_tree_menu(node);
1008 }
1009
1010 /* free node */
1011 node = g_img_iterator_head.next;
1012 while (node)
1013 {
1014 tmp = node->next;
1015 grub_free(node);
1016 node = tmp;
1017 }
1018
1019 /* sort image list by image name */
1020 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1021 {
1022 for (tail = cur->next; tail; tail = tail->next)
1023 {
1024 if (ventoy_cmp_img(cur, tail) > 0)
1025 {
1026 ventoy_swap_img(cur, tail);
1027 }
1028 }
1029 }
1030
1031 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1032 {
1033 g_list_script_pos += grub_snprintf(g_list_script_buf + g_list_script_pos, VTOY_MAX_SCRIPT_BUF - g_list_script_pos,
1034 "menuentry \"%s\" --id=\"VID_%d\" {\n"
1035 " common_menuentry \n"
1036 "}\n",
1037 cur->name, cur->id);
1038 }
1039 g_list_script_buf[g_list_script_pos] = 0;
1040
1041 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1042 grub_env_set(args[1], buf);
1043
1044 fail:
1045
1046 check_free(device_name, grub_free);
1047 check_free(dev, grub_device_close);
1048
1049 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1050 }
1051
1052
1053 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1054 {
1055 img_info *next = NULL;
1056 img_info *cur = g_ventoy_img_list;
1057
1058 (void)ctxt;
1059 (void)argc;
1060 (void)args;
1061
1062 while (cur)
1063 {
1064 next = cur->next;
1065 grub_free(cur);
1066 cur = next;
1067 }
1068
1069 g_ventoy_img_list = NULL;
1070 g_ventoy_img_count = 0;
1071
1072 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1073 }
1074
1075 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1076 {
1077 long img_id = 0;
1078 img_info *cur = g_ventoy_img_list;
1079
1080 (void)ctxt;
1081
1082 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1083 {
1084 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
1085 }
1086
1087 img_id = grub_strtol(args[0], NULL, 10);
1088 if (img_id >= g_ventoy_img_count)
1089 {
1090 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
1091 }
1092
1093 debug("Find image %ld name \n", img_id);
1094
1095 while (cur && img_id > 0)
1096 {
1097 img_id--;
1098 cur = cur->next;
1099 }
1100
1101 if (!cur)
1102 {
1103 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
1104 }
1105
1106 debug("image name is %s\n", cur->name);
1107
1108 grub_env_set(args[1], cur->name);
1109
1110 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1111 }
1112
1113 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
1114 {
1115 int img_id = 0;
1116 char *pos = NULL;
1117 const char *id = NULL;
1118 img_info *cur = g_ventoy_img_list;
1119
1120 (void)ctxt;
1121
1122 if (argc != 1)
1123 {
1124 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
1125 }
1126
1127 id = grub_env_get("chosen");
1128
1129 pos = grub_strstr(id, "VID_");
1130 if (pos)
1131 {
1132 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
1133 }
1134 else
1135 {
1136 img_id = (int)grub_strtoul(id, NULL, 10);
1137 }
1138
1139 while (cur)
1140 {
1141 if (img_id == cur->id)
1142 {
1143 break;
1144 }
1145 cur = cur->next;
1146 }
1147
1148 if (!cur)
1149 {
1150 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
1151 }
1152
1153 grub_env_set(args[0], cur->path);
1154
1155 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1156 }
1157
1158 static int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
1159 {
1160 grub_disk_t disk;
1161 char *device_name;
1162 char *pos;
1163 char *pos2;
1164
1165 device_name = grub_file_get_device_name(filename);
1166 if (!device_name)
1167 {
1168 return 1;
1169 }
1170
1171 pos = device_name;
1172 if (pos[0] == '(')
1173 {
1174 pos++;
1175 }
1176
1177 pos2 = grub_strstr(pos, ",");
1178 if (!pos2)
1179 {
1180 pos2 = grub_strstr(pos, ")");
1181 }
1182
1183 if (pos2)
1184 {
1185 *pos2 = 0;
1186 }
1187
1188 disk = grub_disk_open(pos);
1189 if (disk)
1190 {
1191 grub_disk_read(disk, 0, 0x180, 16, guid);
1192 grub_disk_close(disk);
1193 }
1194 else
1195 {
1196 return 1;
1197 }
1198
1199 grub_free(device_name);
1200 return 0;
1201 }
1202
1203 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
1204 {
1205 eltorito_descriptor desc;
1206
1207 grub_memset(&desc, 0, sizeof(desc));
1208 grub_file_seek(file, 17 * 2048);
1209 grub_file_read(file, &desc, sizeof(desc));
1210
1211 if (desc.type != 0 || desc.version != 1)
1212 {
1213 return 0;
1214 }
1215
1216 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
1217 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
1218 {
1219 return 0;
1220 }
1221
1222 return desc.sector;
1223 }
1224
1225 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
1226 {
1227 int i;
1228 grub_uint8_t buf[512];
1229
1230 grub_file_seek(file, sector * 2048);
1231 grub_file_read(file, buf, sizeof(buf));
1232
1233 if (buf[0] == 0x01 && buf[1] == 0xEF)
1234 {
1235 debug("%s efi eltorito in Validation Entry\n", file->name);
1236 return 1;
1237 }
1238
1239 for (i = 64; i < (int)sizeof(buf); i += 32)
1240 {
1241 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
1242 {
1243 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1244 return 1;
1245 }
1246 }
1247
1248 debug("%s does not contain efi eltorito\n", file->name);
1249 return 0;
1250 }
1251
1252 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1253 {
1254 char *pos;
1255 grub_uint32_t i;
1256 grub_uint8_t chksum = 0;
1257 grub_disk_t disk;
1258
1259 disk = file->device->disk;
1260 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1261
1262 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1263 param->vtoy_disk_part_id = disk->partition->number + 1;
1264 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
1265
1266 pos = grub_strstr(file->name, "/");
1267 if (!pos)
1268 {
1269 pos = file->name;
1270 }
1271
1272 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1273
1274 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1275
1276 param->vtoy_img_size = file->size;
1277
1278 param->vtoy_reserved[0] = g_ventoy_break_level;
1279 param->vtoy_reserved[1] = g_ventoy_debug_level;
1280
1281 /* calculate checksum */
1282 for (i = 0; i < sizeof(ventoy_os_param); i++)
1283 {
1284 chksum += *((grub_uint8_t *)param + i);
1285 }
1286 param->chksum = (grub_uint8_t)(0x100 - chksum);
1287
1288 return;
1289 }
1290
1291 static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1292 {
1293 int fs_type;
1294 grub_uint32_t i = 0;
1295 grub_uint32_t sector = 0;
1296 grub_uint32_t count = 0;
1297 grub_off_t size = 0;
1298 grub_off_t read = 0;
1299
1300 fs_type = ventoy_get_fs_type(file->fs->name);
1301 if (fs_type == ventoy_fs_exfat)
1302 {
1303 grub_fat_get_file_chunk(start, file, chunklist);
1304 }
1305 else
1306 {
1307 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
1308 file->read_hook_data = chunklist;
1309
1310 for (size = file->size; size > 0; size -= read)
1311 {
1312 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
1313 grub_file_read(file, NULL, read);
1314 }
1315
1316 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
1317 {
1318 chunklist->chunk[i].disk_start_sector += start;
1319 chunklist->chunk[i].disk_end_sector += start;
1320 }
1321
1322 if (ventoy_fs_udf == fs_type)
1323 {
1324 for (i = 0; i < chunklist->cur_chunk; i++)
1325 {
1326 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
1327 chunklist->chunk[i].img_start_sector = sector;
1328 chunklist->chunk[i].img_end_sector = sector + count - 1;
1329 sector += count;
1330 }
1331 }
1332 }
1333
1334 return 0;
1335 }
1336
1337 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1338 {
1339 grub_file_t file;
1340
1341 (void)ctxt;
1342 (void)argc;
1343
1344 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1345 if (!file)
1346 {
1347 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1348 }
1349
1350 if (g_img_chunk_list.chunk)
1351 {
1352 grub_free(g_img_chunk_list.chunk);
1353 }
1354
1355 /* get image chunk data */
1356 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1357 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1358 if (NULL == g_img_chunk_list.chunk)
1359 {
1360 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1361 }
1362
1363 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1364 g_img_chunk_list.cur_chunk = 0;
1365
1366 ventoy_get_block_list(file, &g_img_chunk_list, file->device->disk->partition->start);
1367
1368 grub_file_close(file);
1369
1370 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1371
1372 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1373 }
1374
1375 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1376 {
1377 grub_uint32_t i;
1378 ventoy_img_chunk *cur;
1379
1380 (void)ctxt;
1381 (void)argc;
1382 (void)args;
1383
1384 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
1385 {
1386 cur = g_img_chunk_list.chunk + i;
1387 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1388 cur->img_start_sector, cur->img_end_sector,
1389 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
1390 );
1391 }
1392
1393 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1394 }
1395
1396 #ifdef GRUB_MACHINE_EFI
1397 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1398 {
1399 (void)ctxt;
1400 (void)argc;
1401 (void)args;
1402 return 0;
1403 }
1404 #else
1405 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1406 {
1407 int rc = 0;
1408 ulong chain_len = 0;
1409 char *chain_data = NULL;
1410 char *relocator_addr = NULL;
1411 grub_relocator_chunk_t ch;
1412 struct grub_relocator *relocator = NULL;
1413 char envbuf[64] = { 0 };
1414
1415 (void)ctxt;
1416 (void)argc;
1417 (void)args;
1418
1419 if (argc != 2)
1420 {
1421 return 1;
1422 }
1423
1424 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
1425 chain_len = grub_strtoul(args[1], NULL, 10);
1426
1427 relocator = grub_relocator_new ();
1428 if (!relocator)
1429 {
1430 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
1431 return 1;
1432 }
1433
1434 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
1435 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1436 chain_len);
1437 if (rc)
1438 {
1439 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
1440 grub_relocator_unload (relocator);
1441 return 1;
1442 }
1443
1444 relocator_addr = get_virtual_current_address(ch);
1445
1446 grub_memcpy(relocator_addr, chain_data, chain_len);
1447
1448 grub_relocator_unload (relocator);
1449
1450 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
1451 grub_env_set("vtoy_chain_relocator_addr", envbuf);
1452
1453 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1454 }
1455 #endif
1456
1457 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
1458 {
1459 grub_uint32_t i;
1460 grub_file_t file;
1461 ventoy_img_chunk_list chunklist;
1462
1463 (void)ctxt;
1464 (void)argc;
1465
1466 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1467 if (!file)
1468 {
1469 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1470 }
1471
1472 /* get image chunk data */
1473 grub_memset(&chunklist, 0, sizeof(chunklist));
1474 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1475 if (NULL == chunklist.chunk)
1476 {
1477 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1478 }
1479
1480 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
1481 chunklist.cur_chunk = 0;
1482
1483 ventoy_get_block_list(file, &chunklist, 0);
1484
1485 grub_file_close(file);
1486
1487 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
1488
1489 for (i = 0; i < chunklist.cur_chunk; i++)
1490 {
1491 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
1492 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
1493 }
1494
1495 grub_printf("\n==================================\n");
1496 for (i = 0; i < chunklist.cur_chunk; i++)
1497 {
1498 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
1499 (ulonglong)chunklist.chunk[i].img_start_sector,
1500 (ulonglong)chunklist.chunk[i].img_end_sector,
1501 (ulonglong)chunklist.chunk[i].disk_start_sector,
1502 (ulonglong)chunklist.chunk[i].disk_end_sector
1503 );
1504 }
1505
1506 grub_free(chunklist.chunk);
1507
1508 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1509 }
1510
1511 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
1512 {
1513 int i;
1514 ventoy_grub_param_file_replace *replace = NULL;
1515
1516 (void)ctxt;
1517 (void)argc;
1518 (void)args;
1519
1520 if (argc >= 2)
1521 {
1522 replace = &(g_grub_param->file_replace);
1523 replace->magic = GRUB_FILE_REPLACE_MAGIC;
1524
1525 replace->old_name_cnt = 0;
1526 for (i = 0; i < 4 && i + 1 < argc; i++)
1527 {
1528 replace->old_name_cnt++;
1529 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
1530 }
1531
1532 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
1533 }
1534
1535 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1536 }
1537
1538 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1539 {
1540 (void)ctxt;
1541 (void)argc;
1542 (void)args;
1543
1544 if (argc == 0)
1545 {
1546 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
1547 grub_printf("%s", g_list_script_buf);
1548 }
1549 else
1550 {
1551 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
1552 grub_printf("%s", g_tree_script_buf);
1553 }
1554
1555 return 0;
1556 }
1557
1558 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1559 {
1560 (void)ctxt;
1561 (void)argc;
1562 (void)args;
1563
1564 ventoy_plugin_dump_auto_install();
1565
1566 return 0;
1567 }
1568
1569 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
1570 {
1571 (void)ctxt;
1572 (void)argc;
1573 (void)args;
1574
1575 if (argc != 1)
1576 {
1577 return 1;
1578 }
1579
1580 if (args[0][0] == '0')
1581 {
1582 return g_ventoy_memdisk_mode ? 0 : 1;
1583 }
1584 else if (args[0][0] == '1')
1585 {
1586 return g_ventoy_iso_raw ? 0 : 1;
1587 }
1588 else if (args[0][0] == '2')
1589 {
1590 return g_ventoy_iso_uefi_drv ? 0 : 1;
1591 }
1592
1593 return 1;
1594 }
1595
1596 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1597 {
1598 static int configfile_mode = 0;
1599 char memfile[128] = {0};
1600
1601 (void)ctxt;
1602 (void)argc;
1603 (void)args;
1604
1605 /*
1606 * args[0]: 0:normal 1:configfile
1607 * args[1]: 0:list_buf 1:tree_buf
1608 */
1609
1610 if (argc != 2)
1611 {
1612 debug("Invalid argc %d\n", argc);
1613 return 0;
1614 }
1615
1616 if (args[0][0] == '0')
1617 {
1618 if (args[1][0] == '0')
1619 {
1620 grub_script_execute_sourcecode(g_list_script_buf);
1621 }
1622 else
1623 {
1624 grub_script_execute_sourcecode(g_tree_script_buf);
1625 }
1626 }
1627 else
1628 {
1629 if (configfile_mode)
1630 {
1631 debug("Now already in F3 mode %d\n", configfile_mode);
1632 return 0;
1633 }
1634
1635 if (args[1][0] == '0')
1636 {
1637 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1638 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
1639 }
1640 else
1641 {
1642 g_ventoy_last_entry = -1;
1643 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1644 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
1645 }
1646
1647 configfile_mode = 1;
1648 grub_script_execute_sourcecode(memfile);
1649 configfile_mode = 0;
1650 }
1651
1652 return 0;
1653 }
1654
1655 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
1656 {
1657 int id = 0;
1658 int find = 0;
1659 grub_disk_t disk;
1660 const char *isopath = NULL;
1661 char hdname[32];
1662 ventoy_mbr_head mbr;
1663
1664 (void)ctxt;
1665 (void)argc;
1666
1667 if (argc != 1)
1668 {
1669 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
1670 }
1671
1672 isopath = grub_env_get("iso_path");
1673 if (!isopath)
1674 {
1675 debug("isopath is null %p\n", isopath);
1676 return 0;
1677 }
1678
1679 debug("isopath is %s\n", isopath);
1680
1681 for (id = 0; id < 30 && (find == 0); id++)
1682 {
1683 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
1684 if (grub_strstr(isopath, hdname))
1685 {
1686 debug("skip %s ...\n", hdname);
1687 continue;
1688 }
1689
1690 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
1691
1692 disk = grub_disk_open(hdname);
1693 if (!disk)
1694 {
1695 debug("%s not exist\n", hdname);
1696 break;
1697 }
1698
1699 grub_memset(&mbr, 0, sizeof(mbr));
1700 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
1701 {
1702 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
1703 {
1704 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
1705 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
1706 {
1707
1708 grub_env_set(args[0], hdname);
1709 find = 1;
1710 }
1711 }
1712 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
1713 }
1714 else
1715 {
1716 debug("read %s failed\n", hdname);
1717 }
1718
1719 grub_disk_close(disk);
1720 }
1721
1722 return 0;
1723 }
1724
1725 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
1726 {
1727 va_list ap;
1728 grub_file_t file;
1729 char fullpath[256] = {0};
1730
1731 va_start (ap, fmt);
1732 grub_vsnprintf(fullpath, 255, fmt, ap);
1733 va_end (ap);
1734
1735 file = grub_file_open(fullpath, type);
1736 if (!file)
1737 {
1738 debug("grub_file_open failed <%s>\n", fullpath);
1739 grub_errno = 0;
1740 }
1741
1742 return file;
1743 }
1744
1745 int ventoy_is_file_exist(const char *fmt, ...)
1746 {
1747 va_list ap;
1748 int len;
1749 char *pos = NULL;
1750 char buf[256] = {0};
1751
1752 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
1753 pos = buf + 5;
1754
1755 va_start (ap, fmt);
1756 len = grub_vsnprintf(pos, 255, fmt, ap);
1757 va_end (ap);
1758
1759 grub_strncpy(pos + len, " ]", 2);
1760
1761 debug("script exec %s\n", buf);
1762
1763 if (0 == grub_script_execute_sourcecode(buf))
1764 {
1765 return 1;
1766 }
1767
1768 return 0;
1769 }
1770
1771 static int ventoy_env_init(void)
1772 {
1773 char buf[64];
1774
1775 grub_env_set("vtdebug_flag", "");
1776 grub_env_export("vtdebug_flag");
1777
1778 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1779 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1780
1781 ventoy_filt_register(0, ventoy_wrapper_open);
1782
1783 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
1784 if (g_grub_param)
1785 {
1786 g_grub_param->grub_env_get = grub_env_get;
1787 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
1788 grub_env_set("env_param", buf);
1789 }
1790
1791 return 0;
1792 }
1793
1794 static cmd_para ventoy_cmds[] =
1795 {
1796 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
1797 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1798 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1799 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
1800 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
1801 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
1802 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
1803 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
1804 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
1805 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
1806 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
1807 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
1808 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
1809 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
1810 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
1811 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
1812 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
1813 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
1814 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
1815
1816 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
1817 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
1818 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
1819
1820 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1821 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1822 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
1823 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
1824 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
1825 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
1826 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
1827 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
1828 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
1829
1830 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
1831 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
1832 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
1833
1834 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
1835 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
1836 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
1837
1838
1839 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
1840 };
1841
1842
1843
1844 GRUB_MOD_INIT(ventoy)
1845 {
1846 grub_uint32_t i;
1847 cmd_para *cur = NULL;
1848
1849 ventoy_env_init();
1850
1851 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1852 {
1853 cur = ventoy_cmds + i;
1854 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
1855 cur->summary, cur->description, cur->parser);
1856 }
1857 }
1858
1859 GRUB_MOD_FINI(ventoy)
1860 {
1861 grub_uint32_t i;
1862
1863 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1864 {
1865 grub_unregister_extcmd(ventoy_cmds[i].cmd);
1866 }
1867 }
1868