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
)
337 grub_file_t file
= NULL
;
340 char *nextline
= NULL
;
341 initrd_info
*img
= NULL
;
343 debug("grub initrd collect %s\n", fileName
);
345 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
351 buf
= grub_zalloc(file
->size
+ 2);
354 grub_file_close(file
);
358 grub_file_read(file
, buf
, file
->size
);
360 for (start
= buf
; start
; start
= nextline
)
362 nextline
= ventoy_get_line(start
);
364 while (ventoy_isspace(*start
))
369 if (grub_strncmp(start
, "initrd", 6) != 0)
375 while (*start
&& (!ventoy_isspace(*start
)))
380 while (ventoy_isspace(*start
))
387 img
= grub_zalloc(sizeof(initrd_info
));
394 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
396 img
->name
[i
] = *start
++;
397 if (img
->name
[i
] == '$')
403 if (dollar
== 1 || ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
409 if (g_initrd_img_list
)
411 img
->prev
= g_initrd_img_tail
;
412 g_initrd_img_tail
->next
= img
;
416 g_initrd_img_list
= img
;
419 g_initrd_img_tail
= img
;
420 g_initrd_img_count
++;
423 if (*start
== ' ' || *start
== '\t')
425 while (ventoy_isspace(*start
))
438 grub_file_close(file
);
440 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
443 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
446 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
450 debug("ventoy_grub_initrd_hook %s\n", filename
);
452 if (NULL
== grub_strstr(filename
, ".cfg") &&
453 NULL
== grub_strstr(filename
, ".CFG") &&
454 NULL
== grub_strstr(filename
, ".conf"))
459 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
461 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
462 ventoy_grub_cfg_initrd_collect(filePath
);
467 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
470 grub_device_t dev
= NULL
;
471 char *device_name
= NULL
;
472 ventoy_initrd_ctx ctx
;
482 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
484 if (grub_strcmp(args
[0], "file") == 0)
486 return ventoy_grub_cfg_initrd_collect(args
[1]);
489 device_name
= grub_file_get_device_name(args
[1]);
492 debug("failed to get device name %s\n", args
[1]);
496 dev
= grub_device_open(device_name
);
499 debug("failed to open device %s\n", device_name
);
503 fs
= grub_fs_probe(dev
);
506 debug("failed to probe fs %d\n", grub_errno
);
510 ctx
.dir_prefix
= args
[1];
511 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
514 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
518 ctx
.path_prefix
= args
[1];
521 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
523 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
526 check_free(device_name
, grub_free
);
527 check_free(dev
, grub_device_close
);
530 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
533 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
535 initrd_info
*img
= NULL
;
540 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
542 img
= grub_zalloc(sizeof(initrd_info
));
548 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
549 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
551 debug("%s is already exist\n", args
[0]);
556 if (g_initrd_img_list
)
558 img
->prev
= g_initrd_img_tail
;
559 g_initrd_img_tail
->next
= img
;
563 g_initrd_img_list
= img
;
566 g_initrd_img_tail
= img
;
567 g_initrd_img_count
++;
570 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
573 static int ventoy_cpio_newc_get_int(char *value
)
577 grub_memcpy(buf
, value
, 8);
578 return (int)grub_strtoul(buf
, NULL
, 16);
581 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
587 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
589 for (i
= 0; i
< buflen
; i
++)
596 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
600 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
604 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
608 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
609 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
611 namelen
= grub_strlen(name
) + 1;
612 headlen
= sizeof(cpio_newc_header
) + namelen
;
613 headlen
= ventoy_align(headlen
, 4);
615 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
616 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
618 grub_memcpy(cpio
->c_magic
, "070701", 6);
619 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
620 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
621 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
622 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
623 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
624 grub_memcpy(cpio
+ 1, name
, namelen
);
628 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
634 static grub_uint32_t
ventoy_linux_get_virt_chunk_count(void)
636 grub_uint32_t count
= g_valid_initrd_count
;
638 if (g_conf_replace_offset
> 0)
646 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
650 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
652 if (g_conf_replace_offset
> 0)
654 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
;
660 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
664 grub_uint64_t sector
;
665 grub_uint32_t offset
;
666 grub_uint32_t cpio_secs
;
667 grub_uint32_t initrd_secs
;
669 ventoy_virt_chunk
*cur
;
672 override
= (char *)chain
+ chain
->virt_chunk_offset
;
673 sector
= (isosize
+ 2047) / 2048;
674 cpio_secs
= g_ventoy_cpio_size
/ 2048;
676 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
677 cur
= (ventoy_virt_chunk
*)override
;
679 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
686 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
688 cur
->mem_sector_start
= sector
;
689 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
690 cur
->mem_sector_offset
= offset
;
691 cur
->remap_sector_start
= cur
->mem_sector_end
;
692 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
693 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
695 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
697 grub_memset(name
, 0, 16);
698 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
700 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
701 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
703 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
705 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
707 offset
+= g_ventoy_cpio_size
;
708 sector
+= cpio_secs
+ initrd_secs
;
712 if (g_conf_replace_offset
> 0)
714 cpio_secs
= g_conf_replace_new_len_align
/ 2048;
716 cur
->mem_sector_start
= sector
;
717 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
718 cur
->mem_sector_offset
= offset
;
719 cur
->remap_sector_start
= 0;
720 cur
->remap_sector_end
= 0;
721 cur
->org_sector_start
= 0;
723 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
, g_conf_replace_new_len
);
725 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
;
727 offset
+= g_conf_replace_new_len_align
;
735 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
737 grub_uint32_t count
= g_valid_initrd_count
;
739 if (g_conf_replace_offset
> 0)
747 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
749 int count
= g_valid_initrd_count
;
751 if (g_conf_replace_offset
> 0)
756 return sizeof(ventoy_override_chunk
) * count
;
759 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
763 grub_uint32_t newlen
;
764 grub_uint64_t sector
;
765 ventoy_override_chunk
*cur
;
766 ventoy_iso9660_override
*dirent
;
767 ventoy_udf_override
*udf
;
769 sector
= (isosize
+ 2047) / 2048;
771 cur
= (ventoy_override_chunk
*)override
;
772 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
779 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
783 newlen
+= 4 - mod
; /* cpio must align with 4 */
786 if (node
->iso_type
== 0)
788 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
790 node
->override_length
= sizeof(ventoy_iso9660_override
);
791 dirent
->first_sector
= (grub_uint32_t
)sector
;
792 dirent
->size
= newlen
;
793 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
794 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
796 sector
+= (dirent
->size
+ 2047) / 2048;
800 udf
= (ventoy_udf_override
*)node
->override_data
;
802 node
->override_length
= sizeof(ventoy_udf_override
);
803 udf
->length
= newlen
;
804 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
806 sector
+= (udf
->length
+ 2047) / 2048;
809 cur
->img_offset
= node
->override_offset
;
810 cur
->override_size
= node
->override_length
;
811 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
815 if (g_conf_replace_offset
> 0)
817 cur
->img_offset
= g_conf_replace_offset
;
818 cur
->override_size
= sizeof(ventoy_iso9660_override
);
820 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
);
822 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
823 dirent
->first_sector
= (grub_uint32_t
)sector
;
824 dirent
->size
= newlen
;
825 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
826 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
828 sector
+= (dirent
->size
+ 2047) / 2048;
835 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
845 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
846 grub_env_set(args
[0], buf
);
849 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
852 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
862 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
863 grub_env_set(args
[0], buf
);
866 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
869 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
877 debug("ventoy_linux_locate_initrd %d\n", filt
);
879 g_valid_initrd_count
= 0;
881 if (grub_env_get("INITRD_NO_SIZE_FILT"))
886 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
888 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
894 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
896 /* initrd file too small */
898 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
899 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
902 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
904 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
905 grub_file_close(file
);
911 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
914 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
916 grub_file_read(file
, &data
, 1); // just read for hook trigger
917 node
->offset
= grub_iso9660_get_last_read_pos(file
);
924 node
->size
= file
->size
;
925 g_valid_initrd_count
++;
927 grub_file_close(file
);
932 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
936 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
940 initrd_info
*node
= NULL
;
951 if (g_initrd_img_count
== 1)
953 ventoy_set_env(args
[0], "0");
954 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
957 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
964 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
970 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
971 ventoy_set_env(args
[0], buf
);
975 debug("main initrd index:%d\n", index
);
977 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
980 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
988 ventoy_linux_locate_initrd(1, &sizefilt
);
990 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
992 ventoy_linux_locate_initrd(0, &sizefilt
);
995 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
998 static int ventoy_cpio_busybox64(cpio_newc_header
*head
)
1005 name
= (char *)(head
+ 1);
1006 while (name
[0] && count
< 2)
1008 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1010 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1013 else if (grub_strcmp(name
, "ventoy/busybox/64h") == 0)
1015 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1019 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1020 offset
= sizeof(cpio_newc_header
) + namelen
;
1021 offset
= ventoy_align(offset
, 4);
1022 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1023 offset
= ventoy_align(offset
, 4);
1025 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1026 name
= (char *)(head
+ 1);
1033 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1039 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1040 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
);
1045 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1050 char *template_file
= NULL
;
1051 char *template_buf
= NULL
;
1052 char *persistent_buf
= NULL
;
1053 char *injection_buf
= NULL
;
1054 dud
*dudnode
= NULL
;
1056 const char *injection_file
= NULL
;
1057 grub_uint8_t
*buf
= NULL
;
1059 grub_uint32_t headlen
;
1060 grub_uint32_t initrd_head_len
;
1061 grub_uint32_t padlen
;
1062 grub_uint32_t img_chunk_size
;
1063 grub_uint32_t template_size
= 0;
1064 grub_uint32_t persistent_size
= 0;
1065 grub_uint32_t injection_size
= 0;
1066 grub_uint32_t dud_size
= 0;
1068 grub_file_t tmpfile
;
1069 ventoy_img_chunk_list chunk_list
;
1076 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1079 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1081 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1084 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1086 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1089 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1092 if (g_ventoy_cpio_buf
)
1094 grub_free(g_ventoy_cpio_buf
);
1095 g_ventoy_cpio_buf
= NULL
;
1096 g_ventoy_cpio_size
= 0;
1099 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1100 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1102 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1103 persistent_buf
= (char *)(chunk_list
.chunk
);
1106 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1109 debug("auto install template: <%s>\n", template_file
);
1110 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1113 debug("auto install script size %d\n", (int)tmpfile
->size
);
1114 template_size
= tmpfile
->size
;
1115 template_buf
= grub_malloc(template_size
);
1118 grub_file_read(tmpfile
, template_buf
, template_size
);
1121 grub_file_close(tmpfile
);
1125 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1130 debug("auto install script skipped or not configed %s\n", args
[1]);
1133 injection_file
= ventoy_plugin_get_injection(args
[1]);
1136 debug("injection archive: <%s>\n", injection_file
);
1137 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1140 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1141 injection_size
= tmpfile
->size
;
1142 injection_buf
= grub_malloc(injection_size
);
1145 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1148 grub_file_close(tmpfile
);
1152 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1157 debug("injection not configed %s\n", args
[1]);
1160 dudnode
= ventoy_plugin_find_dud(args
[1]);
1163 debug("dud file: <%d>\n", dudnode
->dudnum
);
1164 ventoy_plugin_load_dud(dudnode
, args
[2]);
1165 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1167 if (dudnode
->files
[i
].size
> 0)
1169 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1175 debug("dud not configed %s\n", args
[1]);
1178 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ 40960 + template_size
+
1179 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1180 if (NULL
== g_ventoy_cpio_buf
)
1182 grub_file_close(file
);
1183 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1186 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1188 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1189 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1194 /* get initrd head len */
1195 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1197 /* step1: insert image chunk data to cpio */
1198 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1199 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1203 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1204 buf
+= headlen
+ ventoy_align(template_size
, 4);
1207 if (persistent_size
> 0 && persistent_buf
)
1209 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1210 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1212 grub_free(persistent_buf
);
1213 persistent_buf
= NULL
;
1216 if (injection_size
> 0 && injection_buf
)
1218 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1219 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1221 grub_free(injection_buf
);
1222 injection_buf
= NULL
;
1227 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1229 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1230 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1231 dud_size
= dudnode
->files
[i
].size
;
1232 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1233 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1237 /* step2: insert os param to cpio */
1238 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1239 padlen
= sizeof(ventoy_os_param
);
1240 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1241 mod
= g_ventoy_cpio_size
% 2048;
1244 g_ventoy_cpio_size
+= 2048 - mod
;
1245 padlen
+= 2048 - mod
;
1248 /* update os param data size, the data will be updated before chain boot */
1249 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1250 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1252 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1253 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1254 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1256 grub_file_close(file
);
1258 if (grub_strcmp(args
[3], "busybox=64") == 0)
1260 debug("cpio busybox proc %s\n", args
[3]);
1261 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
);
1264 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1267 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1274 grub_uint8_t
*bufend
;
1275 cpio_newc_header
*head
;
1278 const grub_uint8_t trailler
[124] = {
1279 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1280 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1281 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1282 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1283 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1284 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1285 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1286 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1292 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1298 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1299 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1301 grub_file_close(file
);
1303 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1304 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1306 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1307 mod
= bufsize
% 512;
1310 grub_memset(bufend
, 0, 512 - mod
);
1311 bufsize
+= 512 - mod
;
1314 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1316 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1317 name
= (char *)(head
+ 1);
1319 while (grub_strcmp(name
, "TRAILER!!!"))
1321 if (grub_strcmp(name
, "init") == 0)
1323 grub_memcpy(name
, "xxxx", 4);
1325 else if (grub_strcmp(name
, "linuxrc") == 0)
1327 grub_memcpy(name
, "vtoyxrc", 7);
1329 else if (grub_strcmp(name
, "sbin") == 0)
1331 grub_memcpy(name
, "vtoy", 4);
1333 else if (grub_strcmp(name
, "sbin/init") == 0)
1335 grub_memcpy(name
, "vtoy/vtoy", 9);
1338 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1339 offset
= sizeof(cpio_newc_header
) + namelen
;
1340 offset
= ventoy_align(offset
, 4);
1341 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1342 offset
= ventoy_align(offset
, 4);
1344 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1345 name
= (char *)(head
+ 1);
1349 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1350 ventoy_set_env("ventoy_cpio_addr", value
);
1351 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1352 ventoy_set_env("ventoy_cpio_size", value
);
1354 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1358 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1360 int ventoy_compatible
= 0;
1361 grub_uint32_t size
= 0;
1362 grub_uint64_t isosize
= 0;
1363 grub_uint32_t boot_catlog
= 0;
1364 grub_uint32_t img_chunk_size
= 0;
1365 grub_uint32_t override_count
= 0;
1366 grub_uint32_t override_size
= 0;
1367 grub_uint32_t virt_chunk_count
= 0;
1368 grub_uint32_t virt_chunk_size
= 0;
1371 const char *pLastChain
= NULL
;
1372 const char *compatible
;
1373 ventoy_chain_head
*chain
;
1379 compatible
= grub_env_get("ventoy_compatible");
1380 if (compatible
&& compatible
[0] == 'Y')
1382 ventoy_compatible
= 1;
1385 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1387 grub_printf("ventoy not ready\n");
1391 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1397 isosize
= file
->size
;
1399 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1402 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1404 grub_env_set("LoadIsoEfiDriver", "on");
1409 if (ventoy_is_efi_os())
1411 grub_env_set("LoadIsoEfiDriver", "on");
1415 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1419 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1421 override_count
= ventoy_linux_get_override_chunk_count();
1422 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1424 if (ventoy_compatible
)
1426 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1430 override_size
= ventoy_linux_get_override_chunk_size();
1431 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1432 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1435 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1438 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1441 debug("free last chain memory %p\n", chain
);
1446 chain
= grub_malloc(size
);
1449 grub_printf("Failed to alloc chain memory size %u\n", size
);
1450 grub_file_close(file
);
1454 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1455 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1456 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1457 grub_env_set("vtoy_chain_mem_size", envbuf
);
1459 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1461 /* part 1: os parameter */
1462 g_ventoy_chain_type
= ventoy_chain_linux
;
1463 ventoy_fill_os_param(file
, &(chain
->os_param
));
1465 /* part 2: chain head */
1466 disk
= file
->device
->disk
;
1467 chain
->disk_drive
= disk
->id
;
1468 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1469 chain
->real_img_size_in_bytes
= file
->size
;
1470 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1471 chain
->boot_catalog
= boot_catlog
;
1473 if (!ventoy_is_efi_os())
1475 grub_file_seek(file
, boot_catlog
* 2048);
1476 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1479 /* part 3: image chunk */
1480 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1481 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1482 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1484 if (ventoy_compatible
)
1489 /* part 4: override chunk */
1490 if (override_count
> 0)
1492 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1493 chain
->override_chunk_num
= override_count
;
1494 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1497 /* part 5: virt chunk */
1498 if (virt_chunk_count
> 0)
1500 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1501 chain
->virt_chunk_num
= virt_chunk_count
;
1502 ventoy_linux_fill_virt_data(isosize
, chain
);
1505 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);