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