]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
1.0.09 release
[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_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
1362 {
1363 (void)ctxt;
1364 (void)argc;
1365 (void)args;
1366
1367 ventoy_plugin_dump_auto_install();
1368
1369 return 0;
1370 }
1371
1372 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
1373 {
1374 (void)ctxt;
1375 (void)argc;
1376 (void)args;
1377
1378 if (argc != 1)
1379 {
1380 return 1;
1381 }
1382
1383 if (args[0][0] == '0')
1384 {
1385 return g_ventoy_memdisk_mode ? 0 : 1;
1386 }
1387 else if (args[0][0] == '1')
1388 {
1389 return g_ventoy_iso_raw ? 0 : 1;
1390 }
1391 else if (args[0][0] == '2')
1392 {
1393 return g_ventoy_iso_uefi_drv ? 0 : 1;
1394 }
1395
1396 return 1;
1397 }
1398
1399 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1400 {
1401 static int configfile_mode = 0;
1402 char memfile[128] = {0};
1403
1404 (void)ctxt;
1405 (void)argc;
1406 (void)args;
1407
1408 /*
1409 * args[0]: 0:normal 1:configfile
1410 * args[1]: 0:list_buf 1:tree_buf
1411 */
1412
1413 if (argc != 2)
1414 {
1415 debug("Invlaid argc %d\n", argc);
1416 return 0;
1417 }
1418
1419 if (args[0][0] == '0')
1420 {
1421 if (args[1][0] == '0')
1422 {
1423 grub_script_execute_sourcecode(g_list_script_buf);
1424 }
1425 else
1426 {
1427 grub_script_execute_sourcecode(g_tree_script_buf);
1428 }
1429 }
1430 else
1431 {
1432 if (configfile_mode)
1433 {
1434 debug("Now already in F3 mode %d\n", configfile_mode);
1435 return 0;
1436 }
1437
1438 if (args[1][0] == '0')
1439 {
1440 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1441 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
1442 }
1443 else
1444 {
1445 g_ventoy_last_entry = -1;
1446 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
1447 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
1448 }
1449
1450 configfile_mode = 1;
1451 grub_script_execute_sourcecode(memfile);
1452 configfile_mode = 0;
1453 }
1454
1455 return 0;
1456 }
1457
1458 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
1459 {
1460 int id = 0;
1461 int find = 0;
1462 grub_disk_t disk;
1463 const char *isopath = NULL;
1464 char hdname[32];
1465 ventoy_mbr_head mbr;
1466
1467 (void)ctxt;
1468 (void)argc;
1469
1470 if (argc != 1)
1471 {
1472 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
1473 }
1474
1475 isopath = grub_env_get("iso_path");
1476 if (!isopath)
1477 {
1478 debug("isopath is null %p\n", isopath);
1479 return 0;
1480 }
1481
1482 debug("isopath is %s\n", isopath);
1483
1484 for (id = 0; id < 30 && (find == 0); id++)
1485 {
1486 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
1487 if (grub_strstr(isopath, hdname))
1488 {
1489 debug("skip %s ...\n", hdname);
1490 continue;
1491 }
1492
1493 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
1494
1495 disk = grub_disk_open(hdname);
1496 if (!disk)
1497 {
1498 debug("%s not exist\n", hdname);
1499 break;
1500 }
1501
1502 grub_memset(&mbr, 0, sizeof(mbr));
1503 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
1504 {
1505 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
1506 {
1507 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
1508 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
1509 {
1510
1511 grub_env_set(args[0], hdname);
1512 find = 1;
1513 }
1514 }
1515 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
1516 }
1517 else
1518 {
1519 debug("read %s failed\n", hdname);
1520 }
1521
1522 grub_disk_close(disk);
1523 }
1524
1525 return 0;
1526 }
1527
1528 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
1529 {
1530 va_list ap;
1531 grub_file_t file;
1532 char fullpath[256] = {0};
1533
1534 va_start (ap, fmt);
1535 grub_vsnprintf(fullpath, 255, fmt, ap);
1536 va_end (ap);
1537
1538 file = grub_file_open(fullpath, type);
1539 if (!file)
1540 {
1541 debug("grub_file_open failed <%s>\n", fullpath);
1542 grub_errno = 0;
1543 }
1544
1545 return file;
1546 }
1547
1548 int ventoy_is_file_exist(const char *fmt, ...)
1549 {
1550 va_list ap;
1551 int len;
1552 char *pos = NULL;
1553 char buf[256] = {0};
1554
1555 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
1556 pos = buf + 5;
1557
1558 va_start (ap, fmt);
1559 len = grub_vsnprintf(pos, 255, fmt, ap);
1560 va_end (ap);
1561
1562 grub_strncpy(pos + len, " ]", 2);
1563
1564 debug("script exec %s\n", buf);
1565
1566 if (0 == grub_script_execute_sourcecode(buf))
1567 {
1568 return 1;
1569 }
1570
1571 return 0;
1572 }
1573
1574 static int ventoy_env_init(void)
1575 {
1576 char buf[64];
1577
1578 grub_env_set("vtdebug_flag", "");
1579 grub_env_export("vtdebug_flag");
1580
1581 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1582 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
1583
1584 ventoy_filt_register(0, ventoy_wrapper_open);
1585
1586 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
1587 if (g_grub_param)
1588 {
1589 g_grub_param->grub_env_get = grub_env_get;
1590 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
1591 grub_env_set("env_param", buf);
1592 }
1593
1594 return 0;
1595 }
1596
1597 static cmd_para ventoy_cmds[] =
1598 {
1599 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
1600 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1601 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1602 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
1603 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
1604 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
1605 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
1606 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
1607 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
1608 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
1609 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
1610 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
1611 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
1612 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
1613 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
1614 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
1615 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
1616 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
1617 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
1618
1619 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
1620 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
1621 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
1622
1623 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1624 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1625 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
1626 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
1627 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
1628 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
1629 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
1630 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
1631 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
1632
1633 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
1634 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
1635 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
1636
1637 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
1638
1639
1640 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
1641 };
1642
1643
1644
1645 GRUB_MOD_INIT(ventoy)
1646 {
1647 grub_uint32_t i;
1648 cmd_para *cur = NULL;
1649
1650 ventoy_env_init();
1651
1652 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1653 {
1654 cur = ventoy_cmds + i;
1655 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
1656 cur->summary, cur->description, cur->parser);
1657 }
1658 }
1659
1660 GRUB_MOD_FINI(ventoy)
1661 {
1662 grub_uint32_t i;
1663
1664 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1665 {
1666 grub_unregister_extcmd(ventoy_cmds[i].cmd);
1667 }
1668 }
1669