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 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
916 char *template_file
= NULL
;
917 char *template_buf
= NULL
;
918 char *persistent_buf
= NULL
;
919 char *injection_buf
= NULL
;
920 const char *injection_file
= NULL
;
921 grub_uint8_t
*buf
= NULL
;
923 grub_uint32_t headlen
;
924 grub_uint32_t initrd_head_len
;
925 grub_uint32_t padlen
;
926 grub_uint32_t img_chunk_size
;
927 grub_uint32_t template_size
= 0;
928 grub_uint32_t persistent_size
= 0;
929 grub_uint32_t injection_size
= 0;
932 ventoy_img_chunk_list chunk_list
;
939 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
942 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
944 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
947 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
949 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
952 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
955 if (g_ventoy_cpio_buf
)
957 grub_free(g_ventoy_cpio_buf
);
958 g_ventoy_cpio_buf
= NULL
;
959 g_ventoy_cpio_size
= 0;
962 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
963 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
965 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
966 persistent_buf
= (char *)(chunk_list
.chunk
);
969 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
972 debug("auto install template: <%s>\n", template_file
);
973 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
976 debug("auto install script size %d\n", (int)tmpfile
->size
);
977 template_size
= tmpfile
->size
;
978 template_buf
= grub_malloc(template_size
);
981 grub_file_read(tmpfile
, template_buf
, template_size
);
984 grub_file_close(tmpfile
);
988 debug("Failed to open install script %s%s\n", args
[2], template_file
);
993 debug("auto install script skipped or not configed %s\n", args
[1]);
996 injection_file
= ventoy_plugin_get_injection(args
[1]);
999 debug("injection archive: <%s>\n", injection_file
);
1000 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1003 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1004 injection_size
= tmpfile
->size
;
1005 injection_buf
= grub_malloc(injection_size
);
1008 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1011 grub_file_close(tmpfile
);
1015 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1020 debug("injection not configed %s\n", args
[1]);
1023 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ 4096 + template_size
+ persistent_size
+ injection_size
+ img_chunk_size
);
1024 if (NULL
== g_ventoy_cpio_buf
)
1026 grub_file_close(file
);
1027 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
+ 4096 + img_chunk_size
);
1030 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1032 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1033 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1038 /* get initrd head len */
1039 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1041 /* step1: insert image chunk data to cpio */
1042 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1043 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1047 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1048 buf
+= headlen
+ ventoy_align(template_size
, 4);
1051 if (persistent_size
> 0 && persistent_buf
)
1053 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1054 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1056 grub_free(persistent_buf
);
1057 persistent_buf
= NULL
;
1060 if (injection_size
> 0 && injection_buf
)
1062 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1063 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1065 grub_free(injection_buf
);
1066 injection_buf
= NULL
;
1069 /* step2: insert os param to cpio */
1070 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1071 padlen
= sizeof(ventoy_os_param
);
1072 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1073 mod
= g_ventoy_cpio_size
% 2048;
1076 g_ventoy_cpio_size
+= 2048 - mod
;
1077 padlen
+= 2048 - mod
;
1080 /* update os param data size, the data will be updated before chain boot */
1081 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1082 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1084 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1085 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1086 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1088 grub_file_close(file
);
1090 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1093 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1100 grub_uint8_t
*bufend
;
1101 cpio_newc_header
*head
;
1104 const grub_uint8_t trailler
[124] = {
1105 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1106 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1107 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1108 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1109 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1110 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1111 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1112 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1118 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1124 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1125 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1127 grub_file_close(file
);
1129 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1130 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1132 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1133 mod
= bufsize
% 512;
1136 grub_memset(bufend
, 0, 512 - mod
);
1137 bufsize
+= 512 - mod
;
1140 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1142 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1143 name
= (char *)(head
+ 1);
1145 while (grub_strcmp(name
, "TRAILER!!!"))
1147 if (grub_strcmp(name
, "init") == 0)
1149 grub_memcpy(name
, "xxxx", 4);
1151 else if (grub_strcmp(name
, "linuxrc") == 0)
1153 grub_memcpy(name
, "vtoyxrc", 7);
1155 else if (grub_strcmp(name
, "sbin") == 0)
1157 grub_memcpy(name
, "vtoy", 4);
1159 else if (grub_strcmp(name
, "sbin/init") == 0)
1161 grub_memcpy(name
, "vtoy/vtoy", 9);
1164 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1165 offset
= sizeof(cpio_newc_header
) + namelen
;
1166 offset
= ventoy_align(offset
, 4);
1167 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1168 offset
= ventoy_align(offset
, 4);
1170 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1171 name
= (char *)(head
+ 1);
1175 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1176 ventoy_set_env("ventoy_cpio_addr", value
);
1177 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1178 ventoy_set_env("ventoy_cpio_size", value
);
1180 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1184 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1186 int ventoy_compatible
= 0;
1187 grub_uint32_t size
= 0;
1188 grub_uint64_t isosize
= 0;
1189 grub_uint32_t boot_catlog
= 0;
1190 grub_uint32_t img_chunk_size
= 0;
1191 grub_uint32_t override_size
= 0;
1192 grub_uint32_t virt_chunk_size
= 0;
1195 const char *pLastChain
= NULL
;
1196 const char *compatible
;
1197 ventoy_chain_head
*chain
;
1203 compatible
= grub_env_get("ventoy_compatible");
1204 if (compatible
&& compatible
[0] == 'Y')
1206 ventoy_compatible
= 1;
1209 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1211 grub_printf("ventoy not ready\n");
1215 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1221 isosize
= file
->size
;
1223 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1226 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1228 grub_env_set("LoadIsoEfiDriver", "on");
1233 if (ventoy_is_efi_os())
1235 grub_env_set("LoadIsoEfiDriver", "on");
1239 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1243 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1245 if (ventoy_compatible
)
1247 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1251 override_size
= ventoy_linux_get_override_chunk_size();
1252 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1253 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1256 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1259 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1262 debug("free last chain memory %p\n", chain
);
1267 chain
= grub_malloc(size
);
1270 grub_printf("Failed to alloc chain memory size %u\n", size
);
1271 grub_file_close(file
);
1275 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1276 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1277 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1278 grub_env_set("vtoy_chain_mem_size", envbuf
);
1280 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1282 /* part 1: os parameter */
1283 g_ventoy_chain_type
= ventoy_chain_linux
;
1284 ventoy_fill_os_param(file
, &(chain
->os_param
));
1286 /* part 2: chain head */
1287 disk
= file
->device
->disk
;
1288 chain
->disk_drive
= disk
->id
;
1289 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1290 chain
->real_img_size_in_bytes
= file
->size
;
1291 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1292 chain
->boot_catalog
= boot_catlog
;
1294 if (!ventoy_is_efi_os())
1296 grub_file_seek(file
, boot_catlog
* 2048);
1297 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1300 /* part 3: image chunk */
1301 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1302 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1303 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1305 if (ventoy_compatible
)
1310 if (g_valid_initrd_count
== 0)
1315 /* part 4: override chunk */
1316 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1317 chain
->override_chunk_num
= g_valid_initrd_count
;
1318 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1320 /* part 5: virt chunk */
1321 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1322 chain
->virt_chunk_num
= g_valid_initrd_count
;
1323 ventoy_linux_fill_virt_data(isosize
, chain
);
1325 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);