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);
947 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
950 char *template_file
= NULL
;
951 char *template_buf
= NULL
;
952 char *persistent_buf
= NULL
;
953 char *injection_buf
= NULL
;
954 const char *injection_file
= NULL
;
955 grub_uint8_t
*buf
= NULL
;
957 grub_uint32_t headlen
;
958 grub_uint32_t initrd_head_len
;
959 grub_uint32_t padlen
;
960 grub_uint32_t img_chunk_size
;
961 grub_uint32_t template_size
= 0;
962 grub_uint32_t persistent_size
= 0;
963 grub_uint32_t injection_size
= 0;
966 ventoy_img_chunk_list chunk_list
;
973 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
976 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
978 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
981 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
983 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
986 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
989 if (g_ventoy_cpio_buf
)
991 grub_free(g_ventoy_cpio_buf
);
992 g_ventoy_cpio_buf
= NULL
;
993 g_ventoy_cpio_size
= 0;
996 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
997 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
999 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1000 persistent_buf
= (char *)(chunk_list
.chunk
);
1003 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1006 debug("auto install template: <%s>\n", template_file
);
1007 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1010 debug("auto install script size %d\n", (int)tmpfile
->size
);
1011 template_size
= tmpfile
->size
;
1012 template_buf
= grub_malloc(template_size
);
1015 grub_file_read(tmpfile
, template_buf
, template_size
);
1018 grub_file_close(tmpfile
);
1022 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1027 debug("auto install script skipped or not configed %s\n", args
[1]);
1030 injection_file
= ventoy_plugin_get_injection(args
[1]);
1033 debug("injection archive: <%s>\n", injection_file
);
1034 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1037 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1038 injection_size
= tmpfile
->size
;
1039 injection_buf
= grub_malloc(injection_size
);
1042 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1045 grub_file_close(tmpfile
);
1049 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1054 debug("injection not configed %s\n", args
[1]);
1057 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ 4096 + template_size
+ persistent_size
+ injection_size
+ img_chunk_size
);
1058 if (NULL
== g_ventoy_cpio_buf
)
1060 grub_file_close(file
);
1061 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
+ 4096 + img_chunk_size
);
1064 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1066 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1067 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1072 /* get initrd head len */
1073 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1075 /* step1: insert image chunk data to cpio */
1076 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1077 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1081 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1082 buf
+= headlen
+ ventoy_align(template_size
, 4);
1085 if (persistent_size
> 0 && persistent_buf
)
1087 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1088 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1090 grub_free(persistent_buf
);
1091 persistent_buf
= NULL
;
1094 if (injection_size
> 0 && injection_buf
)
1096 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1097 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1099 grub_free(injection_buf
);
1100 injection_buf
= NULL
;
1103 /* step2: insert os param to cpio */
1104 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1105 padlen
= sizeof(ventoy_os_param
);
1106 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1107 mod
= g_ventoy_cpio_size
% 2048;
1110 g_ventoy_cpio_size
+= 2048 - mod
;
1111 padlen
+= 2048 - mod
;
1114 /* update os param data size, the data will be updated before chain boot */
1115 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1116 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1118 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1119 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1120 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1122 grub_file_close(file
);
1124 if (grub_strcmp(args
[3], "busybox=64") == 0)
1126 debug("cpio busybox proc %s\n", args
[3]);
1127 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
);
1130 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1133 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1140 grub_uint8_t
*bufend
;
1141 cpio_newc_header
*head
;
1144 const grub_uint8_t trailler
[124] = {
1145 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1146 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1147 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1148 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1149 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1150 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1151 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1152 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1158 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1164 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1165 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1167 grub_file_close(file
);
1169 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1170 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1172 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1173 mod
= bufsize
% 512;
1176 grub_memset(bufend
, 0, 512 - mod
);
1177 bufsize
+= 512 - mod
;
1180 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1182 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1183 name
= (char *)(head
+ 1);
1185 while (grub_strcmp(name
, "TRAILER!!!"))
1187 if (grub_strcmp(name
, "init") == 0)
1189 grub_memcpy(name
, "xxxx", 4);
1191 else if (grub_strcmp(name
, "linuxrc") == 0)
1193 grub_memcpy(name
, "vtoyxrc", 7);
1195 else if (grub_strcmp(name
, "sbin") == 0)
1197 grub_memcpy(name
, "vtoy", 4);
1199 else if (grub_strcmp(name
, "sbin/init") == 0)
1201 grub_memcpy(name
, "vtoy/vtoy", 9);
1204 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1205 offset
= sizeof(cpio_newc_header
) + namelen
;
1206 offset
= ventoy_align(offset
, 4);
1207 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1208 offset
= ventoy_align(offset
, 4);
1210 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1211 name
= (char *)(head
+ 1);
1215 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1216 ventoy_set_env("ventoy_cpio_addr", value
);
1217 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1218 ventoy_set_env("ventoy_cpio_size", value
);
1220 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1224 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1226 int ventoy_compatible
= 0;
1227 grub_uint32_t size
= 0;
1228 grub_uint64_t isosize
= 0;
1229 grub_uint32_t boot_catlog
= 0;
1230 grub_uint32_t img_chunk_size
= 0;
1231 grub_uint32_t override_size
= 0;
1232 grub_uint32_t virt_chunk_size
= 0;
1235 const char *pLastChain
= NULL
;
1236 const char *compatible
;
1237 ventoy_chain_head
*chain
;
1243 compatible
= grub_env_get("ventoy_compatible");
1244 if (compatible
&& compatible
[0] == 'Y')
1246 ventoy_compatible
= 1;
1249 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1251 grub_printf("ventoy not ready\n");
1255 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1261 isosize
= file
->size
;
1263 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1266 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1268 grub_env_set("LoadIsoEfiDriver", "on");
1273 if (ventoy_is_efi_os())
1275 grub_env_set("LoadIsoEfiDriver", "on");
1279 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1283 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1285 if (ventoy_compatible
)
1287 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1291 override_size
= ventoy_linux_get_override_chunk_size();
1292 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1293 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1296 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1299 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1302 debug("free last chain memory %p\n", chain
);
1307 chain
= grub_malloc(size
);
1310 grub_printf("Failed to alloc chain memory size %u\n", size
);
1311 grub_file_close(file
);
1315 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1316 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1317 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1318 grub_env_set("vtoy_chain_mem_size", envbuf
);
1320 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1322 /* part 1: os parameter */
1323 g_ventoy_chain_type
= ventoy_chain_linux
;
1324 ventoy_fill_os_param(file
, &(chain
->os_param
));
1326 /* part 2: chain head */
1327 disk
= file
->device
->disk
;
1328 chain
->disk_drive
= disk
->id
;
1329 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1330 chain
->real_img_size_in_bytes
= file
->size
;
1331 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1332 chain
->boot_catalog
= boot_catlog
;
1334 if (!ventoy_is_efi_os())
1336 grub_file_seek(file
, boot_catlog
* 2048);
1337 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1340 /* part 3: image chunk */
1341 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1342 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1343 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1345 if (ventoy_compatible
)
1350 if (g_valid_initrd_count
== 0)
1355 /* part 4: override chunk */
1356 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1357 chain
->override_chunk_num
= g_valid_initrd_count
;
1358 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1360 /* part 5: virt chunk */
1361 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1362 chain
->virt_chunk_num
= g_valid_initrd_count
;
1363 ventoy_linux_fill_virt_data(isosize
, chain
);
1365 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);