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 void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
573 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
575 for (i
= 0; i
< buflen
; i
++)
582 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
586 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
590 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
594 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
595 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
597 namelen
= grub_strlen(name
) + 1;
598 headlen
= sizeof(cpio_newc_header
) + namelen
;
599 headlen
= ventoy_align(headlen
, 4);
601 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
602 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
604 grub_memcpy(cpio
->c_magic
, "070701", 6);
605 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
606 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
607 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
608 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
609 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
610 grub_memcpy(cpio
+ 1, name
, namelen
);
614 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
620 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
622 return (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
625 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
629 grub_uint64_t sector
;
630 grub_uint32_t offset
;
631 grub_uint32_t cpio_secs
;
632 grub_uint32_t initrd_secs
;
634 ventoy_virt_chunk
*cur
;
637 override
= (char *)chain
+ chain
->virt_chunk_offset
;
638 sector
= (isosize
+ 2047) / 2048;
639 cpio_secs
= g_ventoy_cpio_size
/ 2048;
641 offset
= g_valid_initrd_count
* sizeof(ventoy_virt_chunk
);
642 cur
= (ventoy_virt_chunk
*)override
;
644 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
651 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
653 cur
->mem_sector_start
= sector
;
654 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
655 cur
->mem_sector_offset
= offset
;
656 cur
->remap_sector_start
= cur
->mem_sector_end
;
657 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
658 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
660 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
662 grub_memset(name
, 0, 16);
663 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
665 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
666 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
668 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
670 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
672 offset
+= g_ventoy_cpio_size
;
673 sector
+= cpio_secs
+ initrd_secs
;
680 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
682 return sizeof(ventoy_override_chunk
) * g_valid_initrd_count
;
685 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
689 grub_uint32_t newlen
;
690 grub_uint64_t sector
;
691 ventoy_override_chunk
*cur
;
693 sector
= (isosize
+ 2047) / 2048;
695 cur
= (ventoy_override_chunk
*)override
;
696 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
703 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
710 if (node
->iso_type
== 0)
712 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)node
->override_data
;
714 node
->override_length
= sizeof(ventoy_iso9660_override
);
715 dirent
->first_sector
= (grub_uint32_t
)sector
;
716 dirent
->size
= newlen
;
717 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
718 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
720 sector
+= (dirent
->size
+ 2047) / 2048;
724 ventoy_udf_override
*udf
= (ventoy_udf_override
*)node
->override_data
;
726 node
->override_length
= sizeof(ventoy_udf_override
);
727 udf
->length
= newlen
;
728 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
730 sector
+= (udf
->length
+ 2047) / 2048;
733 cur
->img_offset
= node
->override_offset
;
734 cur
->override_size
= node
->override_length
;
735 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
742 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
752 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
753 grub_env_set(args
[0], buf
);
756 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
759 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
769 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
770 grub_env_set(args
[0], buf
);
773 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
776 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
784 debug("ventoy_linux_locate_initrd %d\n", filt
);
786 g_valid_initrd_count
= 0;
788 if (grub_env_get("INITRD_NO_SIZE_FILT"))
793 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
795 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
801 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
803 /* initrd file too small */
805 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
806 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
809 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
811 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
812 grub_file_close(file
);
818 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
821 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
823 grub_file_read(file
, &data
, 1); // just read for hook trigger
824 node
->offset
= grub_iso9660_get_last_read_pos(file
);
831 node
->size
= file
->size
;
832 g_valid_initrd_count
++;
834 grub_file_close(file
);
839 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
843 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
847 initrd_info
*node
= NULL
;
858 if (g_initrd_img_count
== 1)
860 ventoy_set_env(args
[0], "0");
861 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
864 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
871 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
877 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
878 ventoy_set_env(args
[0], buf
);
882 debug("main initrd index:%d\n", index
);
884 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
887 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
895 ventoy_linux_locate_initrd(1, &sizefilt
);
897 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
899 ventoy_linux_locate_initrd(0, &sizefilt
);
902 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
905 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
908 char *template_file
= NULL
;
909 char *template_buf
= NULL
;
910 char *persistent_buf
= NULL
;
911 char *injection_buf
= NULL
;
912 const char *injection_file
= NULL
;
913 grub_uint8_t
*buf
= NULL
;
915 grub_uint32_t headlen
;
916 grub_uint32_t initrd_head_len
;
917 grub_uint32_t padlen
;
918 grub_uint32_t img_chunk_size
;
919 grub_uint32_t template_size
= 0;
920 grub_uint32_t persistent_size
= 0;
921 grub_uint32_t injection_size
= 0;
924 ventoy_img_chunk_list chunk_list
;
931 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
934 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
936 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
939 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
941 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
944 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
947 if (g_ventoy_cpio_buf
)
949 grub_free(g_ventoy_cpio_buf
);
950 g_ventoy_cpio_buf
= NULL
;
951 g_ventoy_cpio_size
= 0;
954 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
955 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
957 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
958 persistent_buf
= (char *)(chunk_list
.chunk
);
961 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
964 debug("auto install template: <%s>\n", template_file
);
965 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
968 debug("auto install script size %d\n", (int)tmpfile
->size
);
969 template_size
= tmpfile
->size
;
970 template_buf
= grub_malloc(template_size
);
973 grub_file_read(tmpfile
, template_buf
, template_size
);
976 grub_file_close(tmpfile
);
980 debug("Failed to open install script %s%s\n", args
[2], template_file
);
985 debug("auto install script skipped or not configed %s\n", args
[1]);
988 injection_file
= ventoy_plugin_get_injection(args
[1]);
991 debug("injection archive: <%s>\n", injection_file
);
992 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
995 debug("injection archive size:%d\n", (int)tmpfile
->size
);
996 injection_size
= tmpfile
->size
;
997 injection_buf
= grub_malloc(injection_size
);
1000 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1003 grub_file_close(tmpfile
);
1007 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1012 debug("injection not configed %s\n", args
[1]);
1015 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ 4096 + template_size
+ persistent_size
+ injection_size
+ img_chunk_size
);
1016 if (NULL
== g_ventoy_cpio_buf
)
1018 grub_file_close(file
);
1019 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
+ 4096 + img_chunk_size
);
1022 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1024 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1025 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1030 /* get initrd head len */
1031 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1033 /* step1: insert image chunk data to cpio */
1034 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1035 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1039 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1040 buf
+= headlen
+ ventoy_align(template_size
, 4);
1043 if (persistent_size
> 0 && persistent_buf
)
1045 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1046 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1048 grub_free(persistent_buf
);
1049 persistent_buf
= NULL
;
1052 if (injection_size
> 0 && injection_buf
)
1054 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1055 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1057 grub_free(injection_buf
);
1058 injection_buf
= NULL
;
1061 /* step2: insert os param to cpio */
1062 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1063 padlen
= sizeof(ventoy_os_param
);
1064 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1065 mod
= g_ventoy_cpio_size
% 2048;
1068 g_ventoy_cpio_size
+= 2048 - mod
;
1069 padlen
+= 2048 - mod
;
1072 /* update os param data size, the data will be updated before chain boot */
1073 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1074 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1076 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1077 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1078 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1080 grub_file_close(file
);
1082 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1086 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1088 int ventoy_compatible
= 0;
1089 grub_uint32_t size
= 0;
1090 grub_uint64_t isosize
= 0;
1091 grub_uint32_t boot_catlog
= 0;
1092 grub_uint32_t img_chunk_size
= 0;
1093 grub_uint32_t override_size
= 0;
1094 grub_uint32_t virt_chunk_size
= 0;
1097 const char *pLastChain
= NULL
;
1098 const char *compatible
;
1099 ventoy_chain_head
*chain
;
1105 compatible
= grub_env_get("ventoy_compatible");
1106 if (compatible
&& compatible
[0] == 'Y')
1108 ventoy_compatible
= 1;
1111 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1113 grub_printf("ventoy not ready\n");
1117 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1123 isosize
= file
->size
;
1125 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1128 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1130 grub_env_set("LoadIsoEfiDriver", "on");
1135 if (ventoy_is_efi_os())
1137 grub_env_set("LoadIsoEfiDriver", "on");
1141 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1145 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1147 if (ventoy_compatible
)
1149 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1153 override_size
= ventoy_linux_get_override_chunk_size();
1154 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1155 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1158 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1161 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1164 debug("free last chain memory %p\n", chain
);
1169 chain
= grub_malloc(size
);
1172 grub_printf("Failed to alloc chain memory size %u\n", size
);
1173 grub_file_close(file
);
1177 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1178 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1179 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1180 grub_env_set("vtoy_chain_mem_size", envbuf
);
1182 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1184 /* part 1: os parameter */
1185 g_ventoy_chain_type
= ventoy_chain_linux
;
1186 ventoy_fill_os_param(file
, &(chain
->os_param
));
1188 /* part 2: chain head */
1189 disk
= file
->device
->disk
;
1190 chain
->disk_drive
= disk
->id
;
1191 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1192 chain
->real_img_size_in_bytes
= file
->size
;
1193 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1194 chain
->boot_catalog
= boot_catlog
;
1196 if (!ventoy_is_efi_os())
1198 grub_file_seek(file
, boot_catlog
* 2048);
1199 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1202 /* part 3: image chunk */
1203 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1204 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1205 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1207 if (ventoy_compatible
)
1212 if (g_valid_initrd_count
== 0)
1217 /* part 4: override chunk */
1218 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1219 chain
->override_chunk_num
= g_valid_initrd_count
;
1220 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1222 /* part 5: virt chunk */
1223 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1224 chain
->virt_chunk_num
= g_valid_initrd_count
;
1225 ventoy_linux_fill_virt_data(isosize
, chain
);
1227 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);