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/>.
20 #include <grub/types.h>
21 #include <grub/misc.h>
25 #include <grub/disk.h>
26 #include <grub/device.h>
27 #include <grub/term.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/normal.h>
31 #include <grub/extcmd.h>
32 #include <grub/datetime.h>
33 #include <grub/i18n.h>
35 #include <grub/time.h>
36 #include <grub/ventoy.h>
37 #include "ventoy_def.h"
39 GRUB_MOD_LICENSE ("GPLv3+");
41 char * ventoy_get_line(char *start
)
48 while (*start
&& *start
!= '\n')
64 static initrd_info
* ventoy_find_initrd_by_name(initrd_info
*list
, const char *name
)
66 initrd_info
*node
= list
;
70 if (grub_strcmp(node
->name
, name
) == 0)
80 grub_err_t
ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
82 initrd_info
*node
= g_initrd_img_list
;
96 g_initrd_img_list
= NULL
;
97 g_initrd_img_tail
= NULL
;
98 g_initrd_img_count
= 0;
99 g_valid_initrd_count
= 0;
101 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
104 grub_err_t
ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
107 initrd_info
*node
= g_initrd_img_list
;
113 grub_printf("###################\n");
114 grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count
);
118 grub_printf("%s ", node
->size
> 0 ? "*" : " ");
119 grub_printf("%02u %s offset:%llu size:%llu \n", i
++, node
->name
, (unsigned long long)node
->offset
,
120 (unsigned long long)node
->size
);
124 grub_printf("###################\n");
126 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
129 static void ventoy_parse_directory(char *path
, char *dir
, int buflen
)
134 pos
= grub_strstr(path
, ")");
140 end
= grub_snprintf(dir
, buflen
, "%s", pos
+ 1);
152 static grub_err_t
ventoy_isolinux_initrd_collect(grub_file_t file
, const char *prefix
)
160 char *nextline
= NULL
;
161 initrd_info
*img
= NULL
;
163 prefixlen
= grub_strlen(prefix
);
165 buf
= grub_zalloc(file
->size
+ 2);
171 grub_file_read(file
, buf
, file
->size
);
173 for (start
= buf
; start
; start
= nextline
)
175 nextline
= ventoy_get_line(start
);
177 while (ventoy_isspace(*start
))
182 offset
= 7; // strlen("initrd=") or "INITRD " or "initrd "
183 pos
= grub_strstr(start
, "initrd=");
188 if (grub_strncmp(start
, "INITRD", 6) != 0 && grub_strncmp(start
, "initrd", 6) != 0)
190 if (grub_strstr(start
, "xen") &&
191 ((pos
= grub_strstr(start
, "--- /install.img")) != NULL
||
192 (pos
= grub_strstr(start
, "--- initrd.img")) != NULL
195 offset
= 4; // "--- "
209 img
= grub_zalloc(sizeof(initrd_info
));
217 grub_strcpy(img
->name
, prefix
);
221 while (i
< 255 && (0 == ventoy_is_word_end(*pos
)))
223 img
->name
[i
++] = *pos
++;
226 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
232 if (g_initrd_img_list
)
234 img
->prev
= g_initrd_img_tail
;
235 g_initrd_img_tail
->next
= img
;
239 g_initrd_img_list
= img
;
242 g_initrd_img_tail
= img
;
243 g_initrd_img_count
++;
258 return GRUB_ERR_NONE
;
261 static int ventoy_isolinux_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
263 grub_file_t file
= NULL
;
264 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
268 if (NULL
== grub_strstr(filename
, ".cfg") && NULL
== grub_strstr(filename
, ".CFG"))
273 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
275 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", ctx
->path_prefix
, filename
);
281 ventoy_isolinux_initrd_collect(file
, ctx
->dir_prefix
);
282 grub_file_close(file
);
287 grub_err_t
ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
290 grub_device_t dev
= NULL
;
291 char *device_name
= NULL
;
292 ventoy_initrd_ctx ctx
;
298 device_name
= grub_file_get_device_name(args
[0]);
304 dev
= grub_device_open(device_name
);
310 fs
= grub_fs_probe(dev
);
316 debug("isolinux initrd collect %s\n", args
[0]);
318 ventoy_parse_directory(args
[0], directory
, sizeof(directory
) - 1);
319 ctx
.path_prefix
= args
[0];
320 ctx
.dir_prefix
= (argc
> 1) ? args
[1] : directory
;
322 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx
.path_prefix
, ctx
.dir_prefix
);
324 fs
->fs_dir(dev
, directory
, ventoy_isolinux_initrd_hook
, &ctx
);
327 check_free(device_name
, grub_free
);
328 check_free(dev
, grub_device_close
);
330 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
333 static grub_err_t
ventoy_grub_cfg_initrd_collect(const char *fileName
)
336 grub_file_t file
= NULL
;
339 char *nextline
= NULL
;
340 initrd_info
*img
= NULL
;
342 debug("grub initrd collect %s\n", fileName
);
344 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
350 buf
= grub_zalloc(file
->size
+ 2);
353 grub_file_close(file
);
357 grub_file_read(file
, buf
, file
->size
);
359 for (start
= buf
; start
; start
= nextline
)
361 nextline
= ventoy_get_line(start
);
363 while (ventoy_isspace(*start
))
368 if (grub_strncmp(start
, "initrd", 6) != 0)
374 while (*start
&& (!ventoy_isspace(*start
)))
379 while (ventoy_isspace(*start
))
386 img
= grub_zalloc(sizeof(initrd_info
));
392 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
394 img
->name
[i
] = *start
++;
397 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
403 if (g_initrd_img_list
)
405 img
->prev
= g_initrd_img_tail
;
406 g_initrd_img_tail
->next
= img
;
410 g_initrd_img_list
= img
;
413 g_initrd_img_tail
= img
;
414 g_initrd_img_count
++;
417 if (*start
== ' ' || *start
== '\t')
419 while (ventoy_isspace(*start
))
432 grub_file_close(file
);
434 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
437 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
440 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
444 debug("ventoy_grub_initrd_hook %s\n", filename
);
446 if (NULL
== grub_strstr(filename
, ".cfg") &&
447 NULL
== grub_strstr(filename
, ".CFG") &&
448 NULL
== grub_strstr(filename
, ".conf"))
453 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
455 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
456 ventoy_grub_cfg_initrd_collect(filePath
);
461 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
464 grub_device_t dev
= NULL
;
465 char *device_name
= NULL
;
466 ventoy_initrd_ctx ctx
;
476 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
478 if (grub_strcmp(args
[0], "file") == 0)
480 return ventoy_grub_cfg_initrd_collect(args
[1]);
483 device_name
= grub_file_get_device_name(args
[1]);
486 debug("failed to get device name %s\n", args
[1]);
490 dev
= grub_device_open(device_name
);
493 debug("failed to open device %s\n", device_name
);
497 fs
= grub_fs_probe(dev
);
500 debug("failed to probe fs %d\n", grub_errno
);
504 ctx
.dir_prefix
= args
[1];
505 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
508 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
512 ctx
.path_prefix
= args
[1];
515 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
517 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
520 check_free(device_name
, grub_free
);
521 check_free(dev
, grub_device_close
);
524 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
527 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
529 initrd_info
*img
= NULL
;
534 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
536 img
= grub_zalloc(sizeof(initrd_info
));
542 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
543 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
545 debug("%s is already exist\n", args
[0]);
550 if (g_initrd_img_list
)
552 img
->prev
= g_initrd_img_tail
;
553 g_initrd_img_tail
->next
= img
;
557 g_initrd_img_list
= img
;
560 g_initrd_img_tail
= img
;
561 g_initrd_img_count
++;
564 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
567 static int ventoy_cpio_newc_get_int(char *value
)
571 grub_memcpy(buf
, value
, 8);
572 return (int)grub_strtoul(buf
, NULL
, 16);
575 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
581 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
583 for (i
= 0; i
< buflen
; i
++)
590 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
594 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
598 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
602 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
603 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
605 namelen
= grub_strlen(name
) + 1;
606 headlen
= sizeof(cpio_newc_header
) + namelen
;
607 headlen
= ventoy_align(headlen
, 4);
609 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
610 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
612 grub_memcpy(cpio
->c_magic
, "070701", 6);
613 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
614 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
615 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
616 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
617 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
618 grub_memcpy(cpio
+ 1, name
, namelen
);
622 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
628 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
630 return (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
633 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
637 grub_uint64_t sector
;
638 grub_uint32_t offset
;
639 grub_uint32_t cpio_secs
;
640 grub_uint32_t initrd_secs
;
642 ventoy_virt_chunk
*cur
;
645 override
= (char *)chain
+ chain
->virt_chunk_offset
;
646 sector
= (isosize
+ 2047) / 2048;
647 cpio_secs
= g_ventoy_cpio_size
/ 2048;
649 offset
= g_valid_initrd_count
* sizeof(ventoy_virt_chunk
);
650 cur
= (ventoy_virt_chunk
*)override
;
652 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
659 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
661 cur
->mem_sector_start
= sector
;
662 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
663 cur
->mem_sector_offset
= offset
;
664 cur
->remap_sector_start
= cur
->mem_sector_end
;
665 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
666 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
668 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
670 grub_memset(name
, 0, 16);
671 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
673 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
674 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
676 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
678 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
680 offset
+= g_ventoy_cpio_size
;
681 sector
+= cpio_secs
+ initrd_secs
;
688 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
690 return sizeof(ventoy_override_chunk
) * g_valid_initrd_count
;
693 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
697 grub_uint32_t newlen
;
698 grub_uint64_t sector
;
699 ventoy_override_chunk
*cur
;
701 sector
= (isosize
+ 2047) / 2048;
703 cur
= (ventoy_override_chunk
*)override
;
704 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
711 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
718 if (node
->iso_type
== 0)
720 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)node
->override_data
;
722 node
->override_length
= sizeof(ventoy_iso9660_override
);
723 dirent
->first_sector
= (grub_uint32_t
)sector
;
724 dirent
->size
= newlen
;
725 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
726 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
728 sector
+= (dirent
->size
+ 2047) / 2048;
732 ventoy_udf_override
*udf
= (ventoy_udf_override
*)node
->override_data
;
734 node
->override_length
= sizeof(ventoy_udf_override
);
735 udf
->length
= newlen
;
736 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
738 sector
+= (udf
->length
+ 2047) / 2048;
741 cur
->img_offset
= node
->override_offset
;
742 cur
->override_size
= node
->override_length
;
743 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
750 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
760 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
761 grub_env_set(args
[0], buf
);
764 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
767 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
777 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
778 grub_env_set(args
[0], buf
);
781 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
784 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
792 debug("ventoy_linux_locate_initrd %d\n", filt
);
794 g_valid_initrd_count
= 0;
796 if (grub_env_get("INITRD_NO_SIZE_FILT"))
801 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
803 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
809 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
811 /* initrd file too small */
813 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
814 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
817 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
819 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
820 grub_file_close(file
);
826 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
829 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
831 grub_file_read(file
, &data
, 1); // just read for hook trigger
832 node
->offset
= grub_iso9660_get_last_read_pos(file
);
839 node
->size
= file
->size
;
840 g_valid_initrd_count
++;
842 grub_file_close(file
);
847 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
851 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
855 initrd_info
*node
= NULL
;
866 if (g_initrd_img_count
== 1)
868 ventoy_set_env(args
[0], "0");
869 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
872 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
879 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
885 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
886 ventoy_set_env(args
[0], buf
);
890 debug("main initrd index:%d\n", index
);
892 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
895 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
903 ventoy_linux_locate_initrd(1, &sizefilt
);
905 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
907 ventoy_linux_locate_initrd(0, &sizefilt
);
910 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
913 static int ventoy_cpio_busybox64(cpio_newc_header
*head
)
920 name
= (char *)(head
+ 1);
921 while (name
[0] && count
< 2)
923 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
925 grub_memcpy(name
, "ventoy/busybox/32h", 18);
928 else if (grub_strcmp(name
, "ventoy/busybox/64h") == 0)
930 grub_memcpy(name
, "ventoy/busybox/ash", 18);
934 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
935 offset
= sizeof(cpio_newc_header
) + namelen
;
936 offset
= ventoy_align(offset
, 4);
937 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
938 offset
= ventoy_align(offset
, 4);
940 head
= (cpio_newc_header
*)((char *)head
+ offset
);
941 name
= (char *)(head
+ 1);
948 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
954 debug("ventoy_cmd_busybox_64 %d\n", argc
);
955 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
);
960 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
963 char *template_file
= NULL
;
964 char *template_buf
= NULL
;
965 char *persistent_buf
= NULL
;
966 char *injection_buf
= NULL
;
967 const char *injection_file
= NULL
;
968 grub_uint8_t
*buf
= NULL
;
970 grub_uint32_t headlen
;
971 grub_uint32_t initrd_head_len
;
972 grub_uint32_t padlen
;
973 grub_uint32_t img_chunk_size
;
974 grub_uint32_t template_size
= 0;
975 grub_uint32_t persistent_size
= 0;
976 grub_uint32_t injection_size
= 0;
979 ventoy_img_chunk_list chunk_list
;
986 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
989 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
991 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
994 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
996 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
999 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1002 if (g_ventoy_cpio_buf
)
1004 grub_free(g_ventoy_cpio_buf
);
1005 g_ventoy_cpio_buf
= NULL
;
1006 g_ventoy_cpio_size
= 0;
1009 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1010 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1012 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1013 persistent_buf
= (char *)(chunk_list
.chunk
);
1016 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1019 debug("auto install template: <%s>\n", template_file
);
1020 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1023 debug("auto install script size %d\n", (int)tmpfile
->size
);
1024 template_size
= tmpfile
->size
;
1025 template_buf
= grub_malloc(template_size
);
1028 grub_file_read(tmpfile
, template_buf
, template_size
);
1031 grub_file_close(tmpfile
);
1035 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1040 debug("auto install script skipped or not configed %s\n", args
[1]);
1043 injection_file
= ventoy_plugin_get_injection(args
[1]);
1046 debug("injection archive: <%s>\n", injection_file
);
1047 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1050 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1051 injection_size
= tmpfile
->size
;
1052 injection_buf
= grub_malloc(injection_size
);
1055 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1058 grub_file_close(tmpfile
);
1062 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1067 debug("injection not configed %s\n", args
[1]);
1070 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ 4096 + template_size
+ persistent_size
+ injection_size
+ img_chunk_size
);
1071 if (NULL
== g_ventoy_cpio_buf
)
1073 grub_file_close(file
);
1074 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
+ 4096 + img_chunk_size
);
1077 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1079 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1080 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1085 /* get initrd head len */
1086 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1088 /* step1: insert image chunk data to cpio */
1089 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1090 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1094 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1095 buf
+= headlen
+ ventoy_align(template_size
, 4);
1098 if (persistent_size
> 0 && persistent_buf
)
1100 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1101 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1103 grub_free(persistent_buf
);
1104 persistent_buf
= NULL
;
1107 if (injection_size
> 0 && injection_buf
)
1109 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1110 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1112 grub_free(injection_buf
);
1113 injection_buf
= NULL
;
1116 /* step2: insert os param to cpio */
1117 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1118 padlen
= sizeof(ventoy_os_param
);
1119 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1120 mod
= g_ventoy_cpio_size
% 2048;
1123 g_ventoy_cpio_size
+= 2048 - mod
;
1124 padlen
+= 2048 - mod
;
1127 /* update os param data size, the data will be updated before chain boot */
1128 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1129 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1131 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1132 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1133 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1135 grub_file_close(file
);
1137 if (grub_strcmp(args
[3], "busybox=64") == 0)
1139 debug("cpio busybox proc %s\n", args
[3]);
1140 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
);
1143 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1146 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1153 grub_uint8_t
*bufend
;
1154 cpio_newc_header
*head
;
1157 const grub_uint8_t trailler
[124] = {
1158 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1159 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1160 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1161 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1162 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1163 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1164 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1165 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1171 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1177 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1178 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1180 grub_file_close(file
);
1182 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1183 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1185 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1186 mod
= bufsize
% 512;
1189 grub_memset(bufend
, 0, 512 - mod
);
1190 bufsize
+= 512 - mod
;
1193 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1195 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1196 name
= (char *)(head
+ 1);
1198 while (grub_strcmp(name
, "TRAILER!!!"))
1200 if (grub_strcmp(name
, "init") == 0)
1202 grub_memcpy(name
, "xxxx", 4);
1204 else if (grub_strcmp(name
, "linuxrc") == 0)
1206 grub_memcpy(name
, "vtoyxrc", 7);
1208 else if (grub_strcmp(name
, "sbin") == 0)
1210 grub_memcpy(name
, "vtoy", 4);
1212 else if (grub_strcmp(name
, "sbin/init") == 0)
1214 grub_memcpy(name
, "vtoy/vtoy", 9);
1217 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1218 offset
= sizeof(cpio_newc_header
) + namelen
;
1219 offset
= ventoy_align(offset
, 4);
1220 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1221 offset
= ventoy_align(offset
, 4);
1223 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1224 name
= (char *)(head
+ 1);
1228 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1229 ventoy_set_env("ventoy_cpio_addr", value
);
1230 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1231 ventoy_set_env("ventoy_cpio_size", value
);
1233 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1237 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1239 int ventoy_compatible
= 0;
1240 grub_uint32_t size
= 0;
1241 grub_uint64_t isosize
= 0;
1242 grub_uint32_t boot_catlog
= 0;
1243 grub_uint32_t img_chunk_size
= 0;
1244 grub_uint32_t override_size
= 0;
1245 grub_uint32_t virt_chunk_size
= 0;
1248 const char *pLastChain
= NULL
;
1249 const char *compatible
;
1250 ventoy_chain_head
*chain
;
1256 compatible
= grub_env_get("ventoy_compatible");
1257 if (compatible
&& compatible
[0] == 'Y')
1259 ventoy_compatible
= 1;
1262 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1264 grub_printf("ventoy not ready\n");
1268 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1274 isosize
= file
->size
;
1276 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1279 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1281 grub_env_set("LoadIsoEfiDriver", "on");
1286 if (ventoy_is_efi_os())
1288 grub_env_set("LoadIsoEfiDriver", "on");
1292 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1296 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1298 if (ventoy_compatible
)
1300 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1304 override_size
= ventoy_linux_get_override_chunk_size();
1305 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1306 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1309 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1312 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1315 debug("free last chain memory %p\n", chain
);
1320 chain
= grub_malloc(size
);
1323 grub_printf("Failed to alloc chain memory size %u\n", size
);
1324 grub_file_close(file
);
1328 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1329 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1330 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1331 grub_env_set("vtoy_chain_mem_size", envbuf
);
1333 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1335 /* part 1: os parameter */
1336 g_ventoy_chain_type
= ventoy_chain_linux
;
1337 ventoy_fill_os_param(file
, &(chain
->os_param
));
1339 /* part 2: chain head */
1340 disk
= file
->device
->disk
;
1341 chain
->disk_drive
= disk
->id
;
1342 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1343 chain
->real_img_size_in_bytes
= file
->size
;
1344 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1345 chain
->boot_catalog
= boot_catlog
;
1347 if (!ventoy_is_efi_os())
1349 grub_file_seek(file
, boot_catlog
* 2048);
1350 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1353 /* part 3: image chunk */
1354 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1355 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1356 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1358 if (ventoy_compatible
)
1363 if (g_valid_initrd_count
== 0)
1368 /* part 4: override chunk */
1369 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1370 chain
->override_chunk_num
= g_valid_initrd_count
;
1371 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1373 /* part 5: virt chunk */
1374 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1375 chain
->virt_chunk_num
= g_valid_initrd_count
;
1376 ventoy_linux_fill_virt_data(isosize
, chain
);
1378 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);