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