1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
21 #include <grub/types.h>
22 #include <grub/misc.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>
36 #ifdef GRUB_MACHINE_EFI
37 #include <grub/efi/efi.h>
39 #include <grub/time.h>
40 #include <grub/ventoy.h>
41 #include "ventoy_def.h"
43 GRUB_MOD_LICENSE ("GPLv3+");
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;
52 static grub_file_t g_old_file
;
54 char g_img_swap_tmp_buf
[1024];
56 img_info
*g_ventoy_img_list
= NULL
;
57 int g_ventoy_img_count
= 0;
59 img_iterator_node g_img_iterator_head
;
61 grub_uint8_t g_ventoy_break_level
= 0;
62 grub_uint8_t g_ventoy_debug_level
= 0;
63 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
64 grub_uint32_t g_ventoy_cpio_size
= 0;
65 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
66 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
68 ventoy_grub_param
*g_grub_param
= NULL
;
70 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
72 ventoy_img_chunk_list g_img_chunk_list
;
74 void ventoy_debug(const char *fmt
, ...)
79 grub_vprintf (fmt
, args
);
83 int ventoy_is_efi_os(void)
87 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
93 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
112 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
114 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
118 static grub_err_t
ventoy_fs_close(grub_file_t file
)
120 grub_file_close(g_old_file
);
121 grub_free(file
->data
);
129 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
133 static struct grub_fs vtoy_fs
=
138 .fs_read
= ventoy_fs_read
,
139 .fs_close
= ventoy_fs_close
,
149 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
155 file
->data
= grub_malloc(rawFile
->size
+ 4096);
161 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
162 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
164 g_old_file
= rawFile
;
166 file
->size
= rawFile
->size
+ len
;
167 file
->device
= rawFile
->device
;
169 file
->not_easily_seekable
= 1;
174 static int ventoy_check_decimal_var(const char *name
, long *value
)
176 const char *value_str
= NULL
;
178 value_str
= grub_env_get(name
);
179 if (NULL
== value_str
)
181 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
184 if (!ventoy_is_decimal(value_str
))
186 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
189 *value
= grub_strtol(value_str
, NULL
, 10);
191 return GRUB_ERR_NONE
;
194 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
198 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
201 if (0 == grub_strcmp(args
[0], "on"))
204 grub_env_set("vtdebug_flag", "debug");
209 grub_env_set("vtdebug_flag", "");
212 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
215 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
219 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
221 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
222 grub_printf(" level:\r\n");
223 grub_printf(" 01/11: busybox / (+cat log)\r\n");
224 grub_printf(" 02/12: initrd / (+cat log)\r\n");
225 grub_printf(" 03/13: hook / (+cat log)\r\n");
227 grub_printf(" debug:\r\n");
228 grub_printf(" 0: debug is on\r\n");
229 grub_printf(" 1: debug is off\r\n");
231 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
234 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
236 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
238 g_ventoy_debug_level
= 1;
241 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
244 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
249 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
251 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
254 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
259 value_long
+= grub_strtol(args
[1], NULL
, 10);
261 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
262 grub_env_set(args
[0], buf
);
264 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
267 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
282 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
285 debug("failed to open file <%s> for udf check\n", args
[0]);
289 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
291 grub_env_set(args
[1], buf
);
293 grub_file_close(file
);
299 static grub_err_t
ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
316 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
319 debug("failed to open file <%s> for udf check\n", args
[0]);
323 #ifdef GRUB_MACHINE_EFI
324 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
326 buf
= (char *)grub_malloc(file
->size
);
329 grub_file_read(file
, buf
, file
->size
);
331 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
332 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
333 grub_env_set(name
, value
);
335 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
336 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
337 grub_env_set(name
, value
);
339 grub_file_close(file
);
345 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
350 grub_uint8_t buf
[32];
361 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
364 debug("failed to open file <%s> for udf check\n", args
[0]);
368 for (i
= 16; i
< 32; i
++)
370 grub_file_seek(file
, i
* 2048);
371 grub_file_read(file
, buf
, sizeof(buf
));
379 grub_file_seek(file
, i
* 2048);
380 grub_file_read(file
, buf
, sizeof(buf
));
382 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
385 grub_file_seek(file
, i
* 2048);
386 grub_file_read(file
, buf
, sizeof(buf
));
388 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
389 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
395 grub_file_close(file
);
397 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
402 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
404 long value_long1
= 0;
405 long value_long2
= 0;
407 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
409 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
412 value_long1
= grub_strtol(args
[0], NULL
, 10);
413 value_long2
= grub_strtol(args
[2], NULL
, 10);
415 if (0 == grub_strcmp(args
[1], "eq"))
417 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
419 else if (0 == grub_strcmp(args
[1], "ne"))
421 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
423 else if (0 == grub_strcmp(args
[1], "gt"))
425 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
427 else if (0 == grub_strcmp(args
[1], "lt"))
429 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
431 else if (0 == grub_strcmp(args
[1], "ge"))
433 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
435 else if (0 == grub_strcmp(args
[1], "le"))
437 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
441 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
447 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
454 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
457 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
458 pos
= grub_strstr(buf
, ",");
464 grub_env_set(args
[1], buf
);
466 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
469 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
475 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
481 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
484 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
486 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
487 if (0 == grub_script_execute_sourcecode(buf
))
489 debug("file %s exist, ventoy_compatible YES\n", buf
);
490 grub_env_set("ventoy_compatible", "YES");
491 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
495 debug("file %s NOT exist\n", buf
);
499 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
500 pos
= grub_strstr(buf
, ")");
506 disk
= grub_disk_open(buf
);
509 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
510 grub_disk_close(disk
);
512 g_img_swap_tmp_buf
[703] = 0;
513 for (i
= 319; i
< 703; i
++)
515 if (g_img_swap_tmp_buf
[i
] == 'V' &&
516 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
518 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
519 grub_env_set("ventoy_compatible", "YES");
520 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
526 debug("failed to open disk <%s>\n", buf
);
529 grub_env_set("ventoy_compatible", "NO");
530 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
533 static int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
539 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
544 if (grub_islower(c1
))
549 if (grub_islower(c2
))
563 static void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
565 grub_memcpy(g_img_swap_tmp_buf
, img1
->name
, sizeof(img1
->name
));
566 grub_memcpy(img1
->name
, img2
->name
, sizeof(img1
->name
));
567 grub_memcpy(img2
->name
, g_img_swap_tmp_buf
, sizeof(img1
->name
));
569 grub_memcpy(g_img_swap_tmp_buf
, img1
->path
, sizeof(img1
->path
));
570 grub_memcpy(img1
->path
, img2
->path
, sizeof(img1
->path
));
571 grub_memcpy(img2
->path
, g_img_swap_tmp_buf
, sizeof(img1
->path
));
574 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
578 for (i
= 0; i
< namelen
; i
++)
580 if (filename
[i
] == ' ' || filename
[i
] == '\t')
585 if ((grub_uint8_t
)(filename
[i
]) >= 127)
594 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
599 img_iterator_node
*new_node
;
600 img_iterator_node
*node
= (img_iterator_node
*)data
;
602 len
= grub_strlen(filename
);
606 if ((len
== 1 && filename
[0] == '.') ||
607 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
612 new_node
= grub_malloc(sizeof(img_iterator_node
));
615 new_node
->tail
= node
->tail
;
616 grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
618 new_node
->next
= g_img_iterator_head
.next
;
619 g_img_iterator_head
.next
= new_node
;
624 debug("Find a file %s\n", filename
);
626 if ((len
> 4) && (0 == grub_strcasecmp(filename
+ len
- 4, ".iso")))
628 if (!ventoy_img_name_valid(filename
, len
))
633 img
= grub_zalloc(sizeof(img_info
));
636 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
637 grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, filename
);
639 if (g_ventoy_img_list
)
641 tail
= *(node
->tail
);
647 g_ventoy_img_list
= img
;
650 *((img_info
**)(node
->tail
)) = img
;
651 g_ventoy_img_count
++;
653 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
661 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
663 int len
= GRUB_UINT_MAX
;
664 const char *value
= NULL
;
667 char guidstr
[32] = {0};
668 ventoy_guid guid
= VENTOY_GUID
;
669 const char *fmt1
= NULL
;
670 const char *fmt2
= NULL
;
671 const char *fmt3
= NULL
;
672 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
673 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
674 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
675 const char fmtcode
[]={
676 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
677 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
678 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
679 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
680 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
681 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
684 grub_memset(name
, 0, sizeof(name
));
685 puint
[0] = grub_swap_bytes32(0x56454e54);
686 puint
[3] = grub_swap_bytes32(0x4f4e0000);
687 puint
[2] = grub_swap_bytes32(0x45525349);
688 puint
[1] = grub_swap_bytes32(0x4f595f56);
689 value
= ventoy_get_env(name
);
691 grub_memset(name
, 0, sizeof(name
));
692 puint
[1] = grub_swap_bytes32(0x5f544f50);
693 puint
[0] = grub_swap_bytes32(0x56544c45);
694 fmt1
= ventoy_get_env(name
);
700 grub_memset(name
, 0, sizeof(name
));
701 puint
[1] = grub_swap_bytes32(0x5f4c4654);
702 puint
[0] = grub_swap_bytes32(0x56544c45);
703 fmt2
= ventoy_get_env(name
);
705 grub_memset(name
, 0, sizeof(name
));
706 puint
[1] = grub_swap_bytes32(0x5f434c52);
707 puint
[0] = grub_swap_bytes32(0x56544c45);
708 fmt3
= ventoy_get_env(name
);
710 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
712 #if defined (GRUB_MACHINE_EFI)
713 puint2
[0] = grub_swap_bytes32(0x55454649);
715 puint2
[0] = grub_swap_bytes32(0x42494f53);
718 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
719 #pragma GCC diagnostic push
720 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
721 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
722 fmt1
? fmt1
: fmtdata
,
723 fmt2
? fmt2
: fmtdata
+ 4,
724 value
? value
: "", plat
, guidstr
,
725 fmt3
? fmt3
: fmtdata
+ 6);
726 #pragma GCC diagnostic pop
728 grub_memset(name
, 0, sizeof(name
));
729 puint
[0] = grub_swap_bytes32(0x76746f79);
730 puint
[2] = grub_swap_bytes32(0x656e7365);
731 puint
[1] = grub_swap_bytes32(0x5f6c6963);
732 ventoy_set_env(name
, guidstr
);
737 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
740 grub_device_t dev
= NULL
;
741 img_info
*cur
= NULL
;
742 img_info
*tail
= NULL
;
743 char *device_name
= NULL
;
745 img_iterator_node
*node
= NULL
;
751 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
754 if (g_ventoy_img_list
|| g_ventoy_img_count
)
756 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
759 device_name
= grub_file_get_device_name(args
[0]);
765 dev
= grub_device_open(device_name
);
771 fs
= grub_fs_probe(dev
);
777 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
779 g_img_iterator_head
.tail
= &tail
;
780 grub_strcpy(g_img_iterator_head
.dir
, "/");
782 fs
->fs_dir(dev
, "/", ventoy_colect_img_files
, &g_img_iterator_head
);
784 while (g_img_iterator_head
.next
)
786 node
= g_img_iterator_head
.next
;
787 g_img_iterator_head
.next
= node
->next
;
789 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
793 /* sort image list by image name */
794 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
796 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
798 if (ventoy_cmp_img(cur
, tail
) > 0)
800 ventoy_swap_img(cur
, tail
);
805 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
806 grub_env_set(args
[1], buf
);
810 check_free(device_name
, grub_free
);
811 check_free(dev
, grub_device_close
);
813 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
817 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
819 img_info
*next
= NULL
;
820 img_info
*cur
= g_ventoy_img_list
;
833 g_ventoy_img_list
= NULL
;
834 g_ventoy_img_count
= 0;
836 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
839 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
842 img_info
*cur
= g_ventoy_img_list
;
846 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
848 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
851 img_id
= grub_strtol(args
[0], NULL
, 10);
852 if (img_id
>= g_ventoy_img_count
)
854 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
857 debug("Find image %ld name \n", img_id
);
859 while (cur
&& img_id
> 0)
867 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
870 debug("image name is %s\n", cur
->name
);
872 grub_env_set(args
[1], cur
->name
);
874 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
877 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
879 const char *name
= NULL
;
880 img_info
*cur
= g_ventoy_img_list
;
886 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
889 name
= grub_env_get("chosen");
893 if (0 == grub_strcmp(name
, cur
->name
))
895 grub_env_set(args
[0], cur
->path
);
903 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
906 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
909 static int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
916 device_name
= grub_file_get_device_name(filename
);
928 pos2
= grub_strstr(pos
, ",");
931 pos2
= grub_strstr(pos
, ")");
939 disk
= grub_disk_open(pos
);
942 grub_disk_read(disk
, 0, 0x180, 16, guid
);
943 grub_disk_close(disk
);
950 grub_free(device_name
);
954 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
956 eltorito_descriptor desc
;
958 grub_memset(&desc
, 0, sizeof(desc
));
959 grub_file_seek(file
, 17 * 2048);
960 grub_file_read(file
, &desc
, sizeof(desc
));
962 if (desc
.type
!= 0 || desc
.version
!= 1)
967 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
968 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
976 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
979 grub_uint8_t buf
[512];
981 grub_file_seek(file
, sector
* 2048);
982 grub_file_read(file
, buf
, sizeof(buf
));
984 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
986 debug("%s efi eltorito in Validation Entry\n", file
->name
);
990 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
992 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
994 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
999 debug("%s does not contain efi eltorito\n", file
->name
);
1003 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1007 grub_uint8_t chksum
= 0;
1010 disk
= file
->device
->disk
;
1011 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1013 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1014 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1016 if (grub_strcmp(file
->fs
->name
, "exfat") == 0)
1018 param
->vtoy_disk_part_type
= 0;
1020 else if (grub_strcmp(file
->fs
->name
, "ntfs") == 0)
1022 param
->vtoy_disk_part_type
= 1;
1026 param
->vtoy_disk_part_type
= 0xFFFF;
1029 pos
= grub_strstr(file
->name
, "/");
1035 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1037 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1039 param
->vtoy_img_size
= file
->size
;
1041 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1042 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1044 /* calculate checksum */
1045 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1047 chksum
+= *((grub_uint8_t
*)param
+ i
);
1049 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1054 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1061 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1064 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1067 if (g_img_chunk_list
.chunk
)
1069 grub_free(g_img_chunk_list
.chunk
);
1072 /* get image chunk data */
1073 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
1074 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1075 if (NULL
== g_img_chunk_list
.chunk
)
1077 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1080 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
1081 g_img_chunk_list
.cur_chunk
= 0;
1083 debug("get fat file chunk part start:%llu\n", (unsigned long long)file
->device
->disk
->partition
->start
);
1084 grub_fat_get_file_chunk(file
->device
->disk
->partition
->start
, file
, &g_img_chunk_list
);
1086 grub_file_close(file
);
1088 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
1090 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1093 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1096 ventoy_img_chunk
*cur
;
1102 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
1104 cur
= g_img_chunk_list
.chunk
+ i
;
1105 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1106 cur
->img_start_sector
, cur
->img_end_sector
,
1107 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
1111 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1114 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1117 ventoy_grub_param_file_replace
*replace
= NULL
;
1125 replace
= &(g_grub_param
->file_replace
);
1126 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
1128 replace
->old_name_cnt
= 0;
1129 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
1131 replace
->old_name_cnt
++;
1132 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
1135 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
1138 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1141 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
1145 char fullpath
[256] = {0};
1148 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
1151 file
= grub_file_open(fullpath
, type
);
1154 debug("grub_file_open failed <%s>\n", fullpath
);
1161 int ventoy_is_file_exist(const char *fmt
, ...)
1166 char buf
[256] = {0};
1168 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
1172 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
1175 grub_strncpy(pos
+ len
, " ]", 2);
1177 debug("script exec %s\n", buf
);
1179 if (0 == grub_script_execute_sourcecode(buf
))
1187 static int ventoy_env_init(void)
1191 grub_env_set("vtdebug_flag", "");
1193 ventoy_filt_register(0, ventoy_wrapper_open
);
1195 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
1198 g_grub_param
->grub_env_get
= grub_env_get
;
1199 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
1200 grub_env_set("env_param", buf
);
1206 static cmd_para ventoy_cmds
[] =
1208 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
1209 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
1210 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
1211 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
1212 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
1213 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
1214 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
1215 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
1216 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
1217 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
1218 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
1219 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
1220 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
1221 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
1223 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
1224 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
1225 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem
, 0, NULL
, "", "", NULL
},
1227 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
1228 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
1229 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
1230 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
1231 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
1232 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
1233 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
1234 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
1235 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
1237 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
1238 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim
, 0, NULL
, "", "", NULL
},
1239 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
1241 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
1244 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
1249 GRUB_MOD_INIT(ventoy
)
1252 cmd_para
*cur
= NULL
;
1256 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
1258 cur
= ventoy_cmds
+ i
;
1259 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
1260 cur
->summary
, cur
->description
, cur
->parser
);
1264 GRUB_MOD_FINI(ventoy
)
1268 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
1270 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);