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