]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
Update PhyDrive.c
[Ventoy.git] / GRUB2 / 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
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 for (i = 0; i < namelen; i++)
622 {
623 if (filename[i] == ' ' || filename[i] == '\t')
624 {
625 return 0;
626 }
627
628 if ((grub_uint8_t)(filename[i]) >= 127)
629 {
630 return 0;
631 }
632 }
633
634 return 1;
635 }
636
637 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
638 {
639 if (0 == info->dir)
640 {
641 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
642 {
643 *((int *)data) = 1;
644 return 0;
645 }
646 }
647
648 return 0;
649 }
650
651 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
652 {
653 int ignore = 0;
654 grub_size_t len;
655 img_info *img;
656 img_info *tail;
657 img_iterator_node *tmp;
658 img_iterator_node *new_node;
659 img_iterator_node *node = (img_iterator_node *)data;
660
661 len = grub_strlen(filename);
662
663 if (info->dir)
664 {
665 if ((len == 1 && filename[0] == '.') ||
666 (len == 2 && filename[0] == '.' && filename[1] == '.'))
667 {
668 return 0;
669 }
670
671 if (!ventoy_img_name_valid(filename, len))
672 {
673 return 0;
674 }
675
676 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
677 {
678 return 0;
679 }
680
681 new_node = grub_zalloc(sizeof(img_iterator_node));
682 if (new_node)
683 {
684 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
685
686 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
687 if (ignore)
688 {
689 debug("Directory %s ignored...\n", new_node->dir);
690 grub_free(new_node);
691 return 0;
692 }
693
694 new_node->tail = node->tail;
695
696 new_node->parent = node;
697 if (!node->firstchild)
698 {
699 node->firstchild = new_node;
700 }
701
702 if (g_img_iterator_tail)
703 {
704 g_img_iterator_tail->next = new_node;
705 g_img_iterator_tail = new_node;
706 }
707 else
708 {
709 g_img_iterator_head.next = new_node;
710 g_img_iterator_tail = new_node;
711 }
712 }
713 }
714 else
715 {
716 debug("Find a file %s\n", filename);
717
718 if ((len > 4) && (0 == grub_strcasecmp(filename + len - 4, ".iso")))
719 {
720 if (!ventoy_img_name_valid(filename, len))
721 {
722 return 0;
723 }
724
725 img = grub_zalloc(sizeof(img_info));
726 if (img)
727 {
728 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
729 grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, filename);
730
731 if (g_ventoy_img_list)
732 {
733 tail = *(node->tail);
734 img->prev = tail;
735 tail->next = img;
736 }
737 else
738 {
739 g_ventoy_img_list = img;
740 }
741
742 img->size = info->size;
743 img->id = g_ventoy_img_count;
744 img->parent = node;
745 if (node && NULL == node->firstiso)
746 {
747 node->firstiso = img;
748 }
749
750 node->isocnt++;
751 tmp = node->parent;
752 while (tmp)
753 {
754 tmp->isocnt++;
755 tmp = tmp->parent;
756 }
757
758 *((img_info **)(node->tail)) = img;
759 g_ventoy_img_count++;
760
761 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
762 }
763 }
764 }
765
766 return 0;
767 }
768
769 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
770 {
771 int len = GRUB_UINT_MAX;
772 const char *value = NULL;
773 char name[32] = {0};
774 char plat[32] = {0};
775 char guidstr[32] = {0};
776 ventoy_guid guid = VENTOY_GUID;
777 const char *fmt1 = NULL;
778 const char *fmt2 = NULL;
779 const char *fmt3 = NULL;
780 grub_uint32_t *puint = (grub_uint32_t *)name;
781 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
782 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
783 const char fmtcode[]={
784 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
785 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
786 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
787 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
788 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
789 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
790 };
791
792 grub_memset(name, 0, sizeof(name));
793 puint[0] = grub_swap_bytes32(0x56454e54);
794 puint[3] = grub_swap_bytes32(0x4f4e0000);
795 puint[2] = grub_swap_bytes32(0x45525349);
796 puint[1] = grub_swap_bytes32(0x4f595f56);
797 value = ventoy_get_env(name);
798
799 grub_memset(name, 0, sizeof(name));
800 puint[1] = grub_swap_bytes32(0x5f544f50);
801 puint[0] = grub_swap_bytes32(0x56544c45);
802 fmt1 = ventoy_get_env(name);
803 if (!fmt1)
804 {
805 fmt1 = fmtdata;
806 }
807
808 grub_memset(name, 0, sizeof(name));
809 puint[1] = grub_swap_bytes32(0x5f4c4654);
810 puint[0] = grub_swap_bytes32(0x56544c45);
811 fmt2 = ventoy_get_env(name);
812
813 grub_memset(name, 0, sizeof(name));
814 puint[1] = grub_swap_bytes32(0x5f434c52);
815 puint[0] = grub_swap_bytes32(0x56544c45);
816 fmt3 = ventoy_get_env(name);
817
818 grub_memcpy(guidstr, &guid, sizeof(guid));
819
820 #if defined (GRUB_MACHINE_EFI)
821 puint2[0] = grub_swap_bytes32(0x55454649);
822 #else
823 puint2[0] = grub_swap_bytes32(0x42494f53);
824 #endif
825
826 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
827 #pragma GCC diagnostic push
828 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
829 len = grub_snprintf(buffer, buflen, fmtcode,
830 fmt1 ? fmt1 : fmtdata,
831 fmt2 ? fmt2 : fmtdata + 4,
832 value ? value : "", plat, guidstr,
833 fmt3 ? fmt3 : fmtdata + 6);
834 #pragma GCC diagnostic pop
835
836 grub_memset(name, 0, sizeof(name));
837 puint[0] = grub_swap_bytes32(0x76746f79);
838 puint[2] = grub_swap_bytes32(0x656e7365);
839 puint[1] = grub_swap_bytes32(0x5f6c6963);
840 ventoy_set_env(name, guidstr);
841
842 return len;
843 }
844
845 static img_info * ventoy_get_min_iso(img_iterator_node *node)
846 {
847 img_info *minimg = NULL;
848 img_info *img = (img_info *)(node->firstiso);
849
850 while (img && (img_iterator_node *)(img->parent) == node)
851 {
852 if (img->select == 0 && (NULL == minimg || grub_strcmp(img->name, minimg->name) < 0))
853 {
854 minimg = img;
855 }
856 img = img->next;
857 }
858
859 if (minimg)
860 {
861 minimg->select = 1;
862 }
863
864 return minimg;
865 }
866
867 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
868 {
869 img_iterator_node *Minchild = NULL;
870 img_iterator_node *child = node->firstchild;
871
872 while (child && child->parent == node)
873 {
874 if (child->select == 0 && (NULL == Minchild || grub_strcmp(child->dir, Minchild->dir) < 0))
875 {
876 Minchild = child;
877 }
878 child = child->next;
879 }
880
881 if (Minchild)
882 {
883 Minchild->select = 1;
884 }
885
886 return Minchild;
887 }
888
889 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
890 {
891 int offset = 1;
892 img_info *img;
893 img_iterator_node *child = NULL;
894
895 if (node->isocnt == 0 || node->done == 1)
896 {
897 return 0;
898 }
899
900 if (node->parent && node->parent->dirlen < node->dirlen)
901 {
902 offset = node->parent->dirlen;
903 }
904
905 if (node != &g_img_iterator_head)
906 {
907 node->dir[node->dirlen - 1] = 0;
908 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
909 "submenu \"%-10s [%s]\" {\n", "DIR", node->dir + offset);
910 }
911
912 while ((child = ventoy_get_min_child(node)) != NULL)
913 {
914 ventoy_dynamic_tree_menu(child);
915 }
916
917 while ((img = ventoy_get_min_iso(node)) != NULL)
918 {
919 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
920 "menuentry \"%-10s %s\" --id=\"VID_%d\" {\n"
921 " common_menuentry \n"
922 "}\n",
923 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->name, img->id);
924 }
925
926 if (node != &g_img_iterator_head)
927 {
928 g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, "}\n");
929 }
930
931 node->done = 1;
932 return 0;
933 }
934
935 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
936 {
937 grub_fs_t fs;
938 grub_device_t dev = NULL;
939 img_info *cur = NULL;
940 img_info *tail = NULL;
941 char *device_name = NULL;
942 char buf[32];
943 img_iterator_node *node = NULL;
944 img_iterator_node *tmp = NULL;
945
946 (void)ctxt;
947
948 if (argc != 2)
949 {
950 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
951 }
952
953 if (g_ventoy_img_list || g_ventoy_img_count)
954 {
955 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
956 }
957
958 device_name = grub_file_get_device_name(args[0]);
959 if (!device_name)
960 {
961 goto fail;
962 }
963
964 g_enum_dev = dev = grub_device_open(device_name);
965 if (!dev)
966 {
967 goto fail;
968 }
969
970 g_enum_fs = fs = grub_fs_probe(dev);
971 if (!fs)
972 {
973 goto fail;
974 }
975
976 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
977 {
978 debug("unsupported fs:<%s>\n", fs->name);
979 goto fail;
980 }
981
982 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
983
984 g_img_iterator_head.dirlen = 1;
985 g_img_iterator_head.tail = &tail;
986 grub_strcpy(g_img_iterator_head.dir, "/");
987
988 for (node = &g_img_iterator_head; node; node = node->next)
989 {
990 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
991 }
992
993 for (node = &g_img_iterator_head; node; node = node->next)
994 {
995 ventoy_dynamic_tree_menu(node);
996 }
997
998 /* free node */
999 node = g_img_iterator_head.next;
1000 while (node)
1001 {
1002 tmp = node->next;
1003 grub_free(node);
1004 node = tmp;
1005 }
1006
1007 /* sort image list by image name */
1008 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1009 {
1010 for (tail = cur->next; tail; tail = tail->next)
1011 {
1012 if (ventoy_cmp_img(cur, tail) > 0)
1013 {
1014 ventoy_swap_img(cur, tail);
1015 }
1016 }
1017 }
1018
1019 for (cur = g_ventoy_img_list; cur; cur = cur->next)
1020 {
1021 g_list_script_pos += grub_snprintf(g_list_script_buf + g_list_script_pos, VTOY_MAX_SCRIPT_BUF - g_list_script_pos,
1022 "menuentry \"%s\" --id=\"VID_%d\" {\n"
1023 " common_menuentry \n"
1024 "}\n",
1025 cur->name, cur->id);
1026 }
1027 g_list_script_buf[g_list_script_pos] = 0;
1028
1029 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
1030 grub_env_set(args[1], buf);
1031
1032 fail:
1033
1034 check_free(device_name, grub_free);
1035 check_free(dev, grub_device_close);
1036
1037 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1038 }
1039
1040
1041 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
1042 {
1043 img_info *next = NULL;
1044 img_info *cur = g_ventoy_img_list;
1045
1046 (void)ctxt;
1047 (void)argc;
1048 (void)args;
1049
1050 while (cur)
1051 {
1052 next = cur->next;
1053 grub_free(cur);
1054 cur = next;
1055 }
1056
1057 g_ventoy_img_list = NULL;
1058 g_ventoy_img_count = 0;
1059
1060 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1061 }
1062
1063 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
1064 {
1065 long img_id = 0;
1066 img_info *cur = g_ventoy_img_list;
1067
1068 (void)ctxt;
1069
1070 if (argc != 2 || (!ventoy_is_decimal(args[0])))
1071 {
1072 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
1073 }
1074
1075 img_id = grub_strtol(args[0], NULL, 10);
1076 if (img_id >= g_ventoy_img_count)
1077 {
1078 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
1079 }
1080
1081 debug("Find image %ld name \n", img_id);
1082
1083 while (cur && img_id > 0)
1084 {
1085 img_id--;
1086 cur = cur->next;
1087 }
1088
1089 if (!cur)
1090 {
1091 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
1092 }
1093
1094 debug("image name is %s\n", cur->name);
1095
1096 grub_env_set(args[1], cur->name);
1097
1098 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1099 }
1100
1101 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
1102 {
1103 int img_id = 0;
1104 char *pos = NULL;
1105 const char *id = NULL;
1106 img_info *cur = g_ventoy_img_list;
1107
1108 (void)ctxt;
1109
1110 if (argc != 1)
1111 {
1112 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
1113 }
1114
1115 id = grub_env_get("chosen");
1116
1117 pos = grub_strstr(id, "VID_");
1118 if (pos)
1119 {
1120 img_id = (int)grub_strtoul(pos + 4, NULL, 10);
1121 }
1122 else
1123 {
1124 img_id = (int)grub_strtoul(id, NULL, 10);
1125 }
1126
1127 while (cur)
1128 {
1129 if (img_id == cur->id)
1130 {
1131 break;
1132 }
1133 cur = cur->next;
1134 }
1135
1136 if (!cur)
1137 {
1138 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
1139 }
1140
1141 grub_env_set(args[0], cur->path);
1142
1143 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1144 }
1145
1146 static int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
1147 {
1148 grub_disk_t disk;
1149 char *device_name;
1150 char *pos;
1151 char *pos2;
1152
1153 device_name = grub_file_get_device_name(filename);
1154 if (!device_name)
1155 {
1156 return 1;
1157 }
1158
1159 pos = device_name;
1160 if (pos[0] == '(')
1161 {
1162 pos++;
1163 }
1164
1165 pos2 = grub_strstr(pos, ",");
1166 if (!pos2)
1167 {
1168 pos2 = grub_strstr(pos, ")");
1169 }
1170
1171 if (pos2)
1172 {
1173 *pos2 = 0;
1174 }
1175
1176 disk = grub_disk_open(pos);
1177 if (disk)
1178 {
1179 grub_disk_read(disk, 0, 0x180, 16, guid);
1180 grub_disk_close(disk);
1181 }
1182 else
1183 {
1184 return 1;
1185 }
1186
1187 grub_free(device_name);
1188 return 0;
1189 }
1190
1191 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
1192 {
1193 eltorito_descriptor desc;
1194
1195 grub_memset(&desc, 0, sizeof(desc));
1196 grub_file_seek(file, 17 * 2048);
1197 grub_file_read(file, &desc, sizeof(desc));
1198
1199 if (desc.type != 0 || desc.version != 1)
1200 {
1201 return 0;
1202 }
1203
1204 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
1205 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
1206 {
1207 return 0;
1208 }
1209
1210 return desc.sector;
1211 }
1212
1213 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
1214 {
1215 int i;
1216 grub_uint8_t buf[512];
1217
1218 grub_file_seek(file, sector * 2048);
1219 grub_file_read(file, buf, sizeof(buf));
1220
1221 if (buf[0] == 0x01 && buf[1] == 0xEF)
1222 {
1223 debug("%s efi eltorito in Validation Entry\n", file->name);
1224 return 1;
1225 }
1226
1227 for (i = 64; i < (int)sizeof(buf); i += 32)
1228 {
1229 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
1230 {
1231 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
1232 return 1;
1233 }
1234 }
1235
1236 debug("%s does not contain efi eltorito\n", file->name);
1237 return 0;
1238 }
1239
1240 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1241 {
1242 char *pos;
1243 grub_uint32_t i;
1244 grub_uint8_t chksum = 0;
1245 grub_disk_t disk;
1246
1247 disk = file->device->disk;
1248 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1249
1250 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1251 param->vtoy_disk_part_id = disk->partition->number + 1;
1252 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
1253
1254 pos = grub_strstr(file->name, "/");
1255 if (!pos)
1256 {
1257 pos = file->name;
1258 }
1259
1260 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1261
1262 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1263
1264 param->vtoy_img_size = file->size;
1265
1266 param->vtoy_reserved[0] = g_ventoy_break_level;
1267 param->vtoy_reserved[1] = g_ventoy_debug_level;
1268
1269 /* calculate checksum */
1270 for (i = 0; i < sizeof(ventoy_os_param); i++)
1271 {
1272 chksum += *((grub_uint8_t *)param + i);
1273 }
1274 param->chksum = (grub_uint8_t)(0x100 - chksum);
1275
1276 return;
1277 }
1278
1279 static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
1280 {
1281 int fs_type;
1282 grub_uint32_t i = 0;
1283 grub_uint32_t sector = 0;
1284 grub_uint32_t count = 0;
1285 grub_off_t size = 0;
1286 grub_off_t read = 0;
1287
1288 fs_type = ventoy_get_fs_type(file->fs->name);
1289 if (fs_type == ventoy_fs_exfat)
1290 {
1291 grub_fat_get_file_chunk(start, file, chunklist);
1292 }
1293 else
1294 {
1295 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
1296 file->read_hook_data = chunklist;
1297
1298 for (size = file->size; size > 0; size -= read)
1299 {
1300 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
1301 grub_file_read(file, NULL, read);
1302 }
1303
1304 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
1305 {
1306 chunklist->chunk[i].disk_start_sector += start;
1307 chunklist->chunk[i].disk_end_sector += start;
1308 }
1309
1310 if (ventoy_fs_udf == fs_type)
1311 {
1312 for (i = 0; i < chunklist->cur_chunk; i++)
1313 {
1314 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
1315 chunklist->chunk[i].img_start_sector = sector;
1316 chunklist->chunk[i].img_end_sector = sector + count - 1;
1317 sector += count;
1318 }
1319 }
1320 }
1321
1322 return 0;
1323 }
1324
1325 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1326 {
1327 grub_file_t file;
1328
1329 (void)ctxt;
1330 (void)argc;
1331
1332 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1333 if (!file)
1334 {
1335 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1336 }
1337
1338 if (g_img_chunk_list.chunk)
1339 {
1340 grub_free(g_img_chunk_list.chunk);
1341 }
1342
1343 /* get image chunk data */
1344 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1345 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1346 if (NULL == g_img_chunk_list.chunk)
1347 {
1348 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1349 }
1350
1351 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1352 g_img_chunk_list.cur_chunk = 0;
1353
1354 ventoy_get_block_list(file, &g_img_chunk_list, file->device->disk->partition->start);
1355
1356 grub_file_close(file);
1357
1358 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1359
1360 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1361 }
1362
1363 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1364 {
1365 grub_uint32_t i;
1366 ventoy_img_chunk *cur;
1367
1368 (void)ctxt;
1369 (void)argc;
1370 (void)args;
1371
1372 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
1373 {
1374 cur = g_img_chunk_list.chunk + i;
1375 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1376 cur->img_start_sector, cur->img_end_sector,
1377 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
1378 );
1379 }
1380
1381 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1382 }
1383
1384 #ifdef GRUB_MACHINE_EFI
1385 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1386 {
1387 (void)ctxt;
1388 (void)argc;
1389 (void)args;
1390 return 0;
1391 }
1392 #else
1393 static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
1394 {
1395 int rc = 0;
1396 ulong chain_len = 0;
1397 char *chain_data = NULL;
1398 char *relocator_addr = NULL;
1399 grub_relocator_chunk_t ch;
1400 struct grub_relocator *relocator = NULL;
1401 char envbuf[64] = { 0 };
1402
1403 (void)ctxt;
1404 (void)argc;
1405 (void)args;
1406
1407 if (argc != 2)
1408 {
1409 return 1;
1410 }
1411
1412 chain_data = (char *)grub_strtoul(args[0], NULL, 16);
1413 chain_len = grub_strtoul(args[1], NULL, 10);
1414
1415 relocator = grub_relocator_new ();
1416 if (!relocator)
1417 {
1418 debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
1419 return 1;
1420 }
1421
1422 rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
1423 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1424 chain_len);
1425 if (rc)
1426 {
1427 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
1428 grub_relocator_unload (relocator);
1429 return 1;
1430 }
1431
1432 relocator_addr = get_virtual_current_address(ch);
1433
1434 grub_memcpy(relocator_addr, chain_data, chain_len);
1435
1436 grub_relocator_unload (relocator);
1437
1438 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
1439 grub_env_set("vtoy_chain_relocator_addr", envbuf);
1440
1441 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1442 }
1443 #endif
1444
1445 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
1446 {
1447 grub_uint32_t i;
1448 grub_file_t file;
1449 ventoy_img_chunk_list chunklist;
1450
1451 (void)ctxt;
1452 (void)argc;
1453
1454 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1455 if (!file)
1456 {
1457 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1458 }
1459
1460 /* get image chunk data */
1461 grub_memset(&chunklist, 0, sizeof(chunklist));
1462 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1463 if (NULL == chunklist.chunk)
1464 {
1465 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1466 }
1467
1468 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
1469 chunklist.cur_chunk = 0;
1470
1471 ventoy_get_block_list(file, &chunklist, 0);
1472
1473 grub_file_close(file);
1474
1475 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
1476
1477 for (i = 0; i < chunklist.cur_chunk; i++)
1478 {
1479 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
1480 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
1481 }
1482
1483 grub_printf("\n==================================\n");
1484 for (i = 0; i < chunklist.cur_chunk; i++)
1485 {
1486 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
1487 (ulonglong)chunklist.chunk[i].img_start_sector,
1488 (ulonglong)chunklist.chunk[i].img_end_sector,
1489 (ulonglong)chunklist.chunk[i].disk_start_sector,
1490 (ulonglong)chunklist.chunk[i].disk_end_sector
1491 );
1492 }
1493
1494 grub_free(chunklist.chunk);
1495
1496 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1497 }
1498
1499 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
1500 {
1501 int i;
1502 ventoy_grub_param_file_replace *replace = NULL;
1503
1504 (void)ctxt;
1505 (void)argc;
1506 (void)args;
1507
1508 if (argc >= 2)
1509 {
1510 replace = &(g_grub_param->file_replace);
1511 replace->magic = GRUB_FILE_REPLACE_MAGIC;
1512
1513 replace->old_name_cnt = 0;
1514 for (i = 0; i < 4 && i + 1 < argc; i++)
1515 {
1516 replace->old_name_cnt++;
1517 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
1518 }
1519
1520 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
1521 }
1522
1523 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1524 }
1525
1526 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1527 {
1528 (void)ctxt;
1529 (void)argc;
1530 (void)args;
1531
1532 if (argc == 0)
1533 {
1534 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
1535 grub_printf("%s", g_list_script_buf);
1536 }
1537 else
1538 {
1539 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
1540 grub_printf("%s", g_tree_script_buf);
1541 }
1542
1543 return 0;
1544 }
1545
1546 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1547 {
1548 (void)ctxt;
1549 (void)argc;
1550 (void)args;
1551
1552 ventoy_plugin_dump_auto_install();
1553
1554 return 0;
1555 }
1556
1557 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
1558 {
1559 (void)ctxt;
1560 (void)argc;
1561 (void)args;
1562
1563 if (argc != 1)
1564 {
1565 return 1;
1566 }
1567
1568 if (args[0][0] == '0')
1569 {
1570 return g_ventoy_memdisk_mode ? 0 : 1;
1571 }
1572 else if (args[0][0] == '1')
1573 {
1574 return g_ventoy_iso_raw ? 0 : 1;
1575 }
1576 else if (args[0][0] == '2')
1577 {
1578 return g_ventoy_iso_uefi_drv ? 0 : 1;
1579 }
1580
1581 return 1;
1582 }
1583
1584 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1585 {
1586 static int configfile_mode = 0;
1587 char memfile[128] = {0};
1588
1589 (void)ctxt;
1590 (void)argc;
1591 (void)args;
1592
1593 /*
1594 * args[0]: 0:normal 1:configfile
1595 * args[1]: 0:list_buf 1:tree_buf
1596 */
1597
1598 if (argc != 2)
1599 {
1600 debug("Invalid argc %d\n", argc);
1601 return 0;
1602 }
1603
1604 if (args[0][0] == '0')
1605 {
1606 if (args[1][0] == '0')
1607 {
1608 grub_script_execute_sourcecode(g_list_script_buf);
1609 }
1610 else
1611 {
1612 grub_script_execute_sourcecode(g_tree_script_buf);
1613 }
1614 }
1615 else
1616 {
1617 if (configfile_mode)
1618 {
1619 debug("Now already in F3 mode %d\n", configfile_mode);
1620 return 0;
1621 }
1622
1623 if (args[1][0] == '0')
1624 {
1625 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1626 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
1627 }
1628 else
1629 {
1630 g_ventoy_last_entry = -1;
1631 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1632 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
1633 }
1634
1635 configfile_mode = 1;
1636 grub_script_execute_sourcecode(memfile);
1637 configfile_mode = 0;
1638 }
1639
1640 return 0;
1641 }
1642
1643 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
1644 {
1645 int id = 0;
1646 int find = 0;
1647 grub_disk_t disk;
1648 const char *isopath = NULL;
1649 char hdname[32];
1650 ventoy_mbr_head mbr;
1651
1652 (void)ctxt;
1653 (void)argc;
1654
1655 if (argc != 1)
1656 {
1657 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
1658 }
1659
1660 isopath = grub_env_get("iso_path");
1661 if (!isopath)
1662 {
1663 debug("isopath is null %p\n", isopath);
1664 return 0;
1665 }
1666
1667 debug("isopath is %s\n", isopath);
1668
1669 for (id = 0; id < 30 && (find == 0); id++)
1670 {
1671 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
1672 if (grub_strstr(isopath, hdname))
1673 {
1674 debug("skip %s ...\n", hdname);
1675 continue;
1676 }
1677
1678 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
1679
1680 disk = grub_disk_open(hdname);
1681 if (!disk)
1682 {
1683 debug("%s not exist\n", hdname);
1684 break;
1685 }
1686
1687 grub_memset(&mbr, 0, sizeof(mbr));
1688 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
1689 {
1690 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
1691 {
1692 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
1693 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
1694 {
1695
1696 grub_env_set(args[0], hdname);
1697 find = 1;
1698 }
1699 }
1700 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
1701 }
1702 else
1703 {
1704 debug("read %s failed\n", hdname);
1705 }
1706
1707 grub_disk_close(disk);
1708 }
1709
1710 return 0;
1711 }
1712
1713 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
1714 {
1715 va_list ap;
1716 grub_file_t file;
1717 char fullpath[256] = {0};
1718
1719 va_start (ap, fmt);
1720 grub_vsnprintf(fullpath, 255, fmt, ap);
1721 va_end (ap);
1722
1723 file = grub_file_open(fullpath, type);
1724 if (!file)
1725 {
1726 debug("grub_file_open failed <%s>\n", fullpath);
1727 grub_errno = 0;
1728 }
1729
1730 return file;
1731 }
1732
1733 int ventoy_is_file_exist(const char *fmt, ...)
1734 {
1735 va_list ap;
1736 int len;
1737 char *pos = NULL;
1738 char buf[256] = {0};
1739
1740 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
1741 pos = buf + 5;
1742
1743 va_start (ap, fmt);
1744 len = grub_vsnprintf(pos, 255, fmt, ap);
1745 va_end (ap);
1746
1747 grub_strncpy(pos + len, " ]", 2);
1748
1749 debug("script exec %s\n", buf);
1750
1751 if (0 == grub_script_execute_sourcecode(buf))
1752 {
1753 return 1;
1754 }
1755
1756 return 0;
1757 }
1758
1759 static int ventoy_env_init(void)
1760 {
1761 char buf[64];
1762
1763 grub_env_set("vtdebug_flag", "");
1764 grub_env_export("vtdebug_flag");
1765
1766 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1767 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1768
1769 ventoy_filt_register(0, ventoy_wrapper_open);
1770
1771 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
1772 if (g_grub_param)
1773 {
1774 g_grub_param->grub_env_get = grub_env_get;
1775 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
1776 grub_env_set("env_param", buf);
1777 }
1778
1779 return 0;
1780 }
1781
1782 static cmd_para ventoy_cmds[] =
1783 {
1784 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
1785 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1786 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1787 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
1788 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
1789 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
1790 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
1791 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
1792 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
1793 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
1794 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
1795 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
1796 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
1797 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
1798 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
1799 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
1800 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
1801 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
1802 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
1803
1804 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
1805 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
1806 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
1807
1808 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1809 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1810 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
1811 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
1812 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
1813 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
1814 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
1815 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
1816 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
1817
1818 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
1819 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
1820 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
1821
1822 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
1823 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
1824 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
1825
1826
1827 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
1828 };
1829
1830
1831
1832 GRUB_MOD_INIT(ventoy)
1833 {
1834 grub_uint32_t i;
1835 cmd_para *cur = NULL;
1836
1837 ventoy_env_init();
1838
1839 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1840 {
1841 cur = ventoy_cmds + i;
1842 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
1843 cur->summary, cur->description, cur->parser);
1844 }
1845 }
1846
1847 GRUB_MOD_FINI(ventoy)
1848 {
1849 grub_uint32_t i;
1850
1851 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1852 {
1853 grub_unregister_extcmd(ventoy_cmds[i].cmd);
1854 }
1855 }
1856