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)
744 if (g_svd_replace_offset
> 0)
752 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
754 int count
= g_valid_initrd_count
;
756 if (g_conf_replace_offset
> 0)
761 if (g_svd_replace_offset
> 0)
766 return sizeof(ventoy_override_chunk
) * count
;
769 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
773 grub_uint32_t newlen
;
774 grub_uint64_t sector
;
775 ventoy_override_chunk
*cur
;
776 ventoy_iso9660_override
*dirent
;
777 ventoy_udf_override
*udf
;
779 sector
= (isosize
+ 2047) / 2048;
781 cur
= (ventoy_override_chunk
*)override
;
782 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
789 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
793 newlen
+= 4 - mod
; /* cpio must align with 4 */
796 if (node
->iso_type
== 0)
798 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
800 node
->override_length
= sizeof(ventoy_iso9660_override
);
801 dirent
->first_sector
= (grub_uint32_t
)sector
;
802 dirent
->size
= newlen
;
803 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
804 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
806 sector
+= (dirent
->size
+ 2047) / 2048;
810 udf
= (ventoy_udf_override
*)node
->override_data
;
812 node
->override_length
= sizeof(ventoy_udf_override
);
813 udf
->length
= newlen
;
814 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
816 sector
+= (udf
->length
+ 2047) / 2048;
819 cur
->img_offset
= node
->override_offset
;
820 cur
->override_size
= node
->override_length
;
821 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
825 if (g_conf_replace_offset
> 0)
827 cur
->img_offset
= g_conf_replace_offset
;
828 cur
->override_size
= sizeof(ventoy_iso9660_override
);
830 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
);
832 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
833 dirent
->first_sector
= (grub_uint32_t
)sector
;
834 dirent
->size
= newlen
;
835 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
836 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
838 sector
+= (dirent
->size
+ 2047) / 2048;
842 if (g_svd_replace_offset
> 0)
844 cur
->img_offset
= g_svd_replace_offset
;
845 cur
->override_size
= 1;
846 cur
->override_data
[0] = 0xFF;
853 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
863 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
864 grub_env_set(args
[0], buf
);
867 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
870 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
880 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
881 grub_env_set(args
[0], buf
);
884 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
887 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
895 debug("ventoy_linux_locate_initrd %d\n", filt
);
897 g_valid_initrd_count
= 0;
899 if (grub_env_get("INITRD_NO_SIZE_FILT"))
904 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
906 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
912 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
914 /* initrd file too small */
916 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
917 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
920 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
922 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
923 grub_file_close(file
);
929 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
932 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
934 grub_file_read(file
, &data
, 1); // just read for hook trigger
935 node
->offset
= grub_iso9660_get_last_read_pos(file
);
942 node
->size
= file
->size
;
943 g_valid_initrd_count
++;
945 grub_file_close(file
);
950 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
954 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
958 initrd_info
*node
= NULL
;
969 if (g_initrd_img_count
== 1)
971 ventoy_set_env(args
[0], "0");
972 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
975 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
982 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
988 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
989 ventoy_set_env(args
[0], buf
);
993 debug("main initrd index:%d\n", index
);
995 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
998 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1006 ventoy_linux_locate_initrd(1, &sizefilt
);
1008 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1010 ventoy_linux_locate_initrd(0, &sizefilt
);
1013 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1016 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1024 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1026 name
= (char *)(head
+ 1);
1027 while (name
[0] && count
< 2)
1029 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1031 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1034 else if (grub_strcmp(name
, filepath
) == 0)
1036 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1040 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1041 offset
= sizeof(cpio_newc_header
) + namelen
;
1042 offset
= ventoy_align(offset
, 4);
1043 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1044 offset
= ventoy_align(offset
, 4);
1046 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1047 name
= (char *)(head
+ 1);
1054 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1060 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1061 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1065 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1074 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1077 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1080 for (i
= 0; i
< 10; i
++)
1083 grub_file_seek(file
, (17 + i
) * 2048);
1084 grub_file_read(file
, buf
, 16);
1086 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1088 debug("Find SVD at VD %d\n", i
);
1089 g_svd_replace_offset
= (17 + i
) * 2048;
1096 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1099 grub_file_close(file
);
1101 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1104 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1109 char *template_file
= NULL
;
1110 char *template_buf
= NULL
;
1111 char *persistent_buf
= NULL
;
1112 char *injection_buf
= NULL
;
1113 dud
*dudnode
= NULL
;
1115 const char *injection_file
= NULL
;
1116 grub_uint8_t
*buf
= NULL
;
1118 grub_uint32_t headlen
;
1119 grub_uint32_t initrd_head_len
;
1120 grub_uint32_t padlen
;
1121 grub_uint32_t img_chunk_size
;
1122 grub_uint32_t template_size
= 0;
1123 grub_uint32_t persistent_size
= 0;
1124 grub_uint32_t injection_size
= 0;
1125 grub_uint32_t dud_size
= 0;
1127 grub_file_t archfile
;
1128 grub_file_t tmpfile
;
1129 ventoy_img_chunk_list chunk_list
;
1136 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1139 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1141 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1144 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1146 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1149 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1152 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1155 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1156 grub_file_close(file
);
1159 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1161 if (g_ventoy_cpio_buf
)
1163 grub_free(g_ventoy_cpio_buf
);
1164 g_ventoy_cpio_buf
= NULL
;
1165 g_ventoy_cpio_size
= 0;
1168 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1169 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1171 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1172 persistent_buf
= (char *)(chunk_list
.chunk
);
1175 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1178 debug("auto install template: <%s>\n", template_file
);
1179 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1182 debug("auto install script size %d\n", (int)tmpfile
->size
);
1183 template_size
= tmpfile
->size
;
1184 template_buf
= grub_malloc(template_size
);
1187 grub_file_read(tmpfile
, template_buf
, template_size
);
1190 grub_file_close(tmpfile
);
1194 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1199 debug("auto install script skipped or not configed %s\n", args
[1]);
1202 injection_file
= ventoy_plugin_get_injection(args
[1]);
1205 debug("injection archive: <%s>\n", injection_file
);
1206 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1209 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1210 injection_size
= tmpfile
->size
;
1211 injection_buf
= grub_malloc(injection_size
);
1214 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1217 grub_file_close(tmpfile
);
1221 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1226 debug("injection not configed %s\n", args
[1]);
1229 dudnode
= ventoy_plugin_find_dud(args
[1]);
1232 debug("dud file: <%d>\n", dudnode
->dudnum
);
1233 ventoy_plugin_load_dud(dudnode
, args
[2]);
1234 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1236 if (dudnode
->files
[i
].size
> 0)
1238 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1244 debug("dud not configed %s\n", args
[1]);
1247 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1248 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1249 if (NULL
== g_ventoy_cpio_buf
)
1251 grub_file_close(file
);
1252 grub_file_close(archfile
);
1253 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1256 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1257 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1258 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1263 grub_file_read(archfile
, buf
, archfile
->size
);
1264 buf
+= (archfile
->size
- 4);
1265 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1270 /* get initrd head len */
1271 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1273 /* step1: insert image chunk data to cpio */
1274 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1275 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1279 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1280 buf
+= headlen
+ ventoy_align(template_size
, 4);
1283 if (persistent_size
> 0 && persistent_buf
)
1285 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1286 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1288 grub_free(persistent_buf
);
1289 persistent_buf
= NULL
;
1292 if (injection_size
> 0 && injection_buf
)
1294 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1295 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1297 grub_free(injection_buf
);
1298 injection_buf
= NULL
;
1303 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1305 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1306 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1307 dud_size
= dudnode
->files
[i
].size
;
1308 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1309 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1313 /* step2: insert os param to cpio */
1314 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1315 padlen
= sizeof(ventoy_os_param
);
1316 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1317 mod
= g_ventoy_cpio_size
% 2048;
1320 g_ventoy_cpio_size
+= 2048 - mod
;
1321 padlen
+= 2048 - mod
;
1324 /* update os param data size, the data will be updated before chain boot */
1325 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1326 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1328 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1329 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1330 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1332 grub_file_close(file
);
1333 grub_file_close(archfile
);
1335 if (grub_strcmp(args
[3], "busybox=64") == 0)
1337 debug("cpio busybox proc %s\n", args
[3]);
1338 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1340 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1342 debug("cpio busybox proc %s\n", args
[3]);
1343 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1345 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1347 debug("cpio busybox proc %s\n", args
[3]);
1348 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1351 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1354 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1361 grub_uint8_t
*bufend
;
1362 cpio_newc_header
*head
;
1365 const grub_uint8_t trailler
[124] = {
1366 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1367 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1368 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1369 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1370 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1371 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1372 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1373 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1379 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1385 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1386 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1388 grub_file_close(file
);
1390 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1391 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1393 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1394 mod
= bufsize
% 512;
1397 grub_memset(bufend
, 0, 512 - mod
);
1398 bufsize
+= 512 - mod
;
1401 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1403 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1404 name
= (char *)(head
+ 1);
1406 while (grub_strcmp(name
, "TRAILER!!!"))
1408 if (grub_strcmp(name
, "init") == 0)
1410 grub_memcpy(name
, "xxxx", 4);
1412 else if (grub_strcmp(name
, "linuxrc") == 0)
1414 grub_memcpy(name
, "vtoyxrc", 7);
1416 else if (grub_strcmp(name
, "sbin") == 0)
1418 grub_memcpy(name
, "vtoy", 4);
1420 else if (grub_strcmp(name
, "sbin/init") == 0)
1422 grub_memcpy(name
, "vtoy/vtoy", 9);
1425 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1426 offset
= sizeof(cpio_newc_header
) + namelen
;
1427 offset
= ventoy_align(offset
, 4);
1428 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1429 offset
= ventoy_align(offset
, 4);
1431 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1432 name
= (char *)(head
+ 1);
1436 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1437 ventoy_set_env("ventoy_cpio_addr", value
);
1438 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1439 ventoy_set_env("ventoy_cpio_size", value
);
1441 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1445 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1447 int ventoy_compatible
= 0;
1448 grub_uint32_t size
= 0;
1449 grub_uint64_t isosize
= 0;
1450 grub_uint32_t boot_catlog
= 0;
1451 grub_uint32_t img_chunk_size
= 0;
1452 grub_uint32_t override_count
= 0;
1453 grub_uint32_t override_size
= 0;
1454 grub_uint32_t virt_chunk_count
= 0;
1455 grub_uint32_t virt_chunk_size
= 0;
1458 const char *pLastChain
= NULL
;
1459 const char *compatible
;
1460 ventoy_chain_head
*chain
;
1466 compatible
= grub_env_get("ventoy_compatible");
1467 if (compatible
&& compatible
[0] == 'Y')
1469 ventoy_compatible
= 1;
1472 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1474 grub_printf("ventoy not ready\n");
1478 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1484 isosize
= file
->size
;
1486 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1489 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1491 grub_env_set("LoadIsoEfiDriver", "on");
1496 if (ventoy_is_efi_os())
1498 grub_env_set("LoadIsoEfiDriver", "on");
1502 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1506 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1508 override_count
= ventoy_linux_get_override_chunk_count();
1509 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1511 if (ventoy_compatible
)
1513 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1517 override_size
= ventoy_linux_get_override_chunk_size();
1518 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1519 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1522 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1525 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1528 debug("free last chain memory %p\n", chain
);
1533 chain
= grub_malloc(size
);
1536 grub_printf("Failed to alloc chain memory size %u\n", size
);
1537 grub_file_close(file
);
1541 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1542 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1543 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1544 grub_env_set("vtoy_chain_mem_size", envbuf
);
1546 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1548 /* part 1: os parameter */
1549 g_ventoy_chain_type
= ventoy_chain_linux
;
1550 ventoy_fill_os_param(file
, &(chain
->os_param
));
1552 /* part 2: chain head */
1553 disk
= file
->device
->disk
;
1554 chain
->disk_drive
= disk
->id
;
1555 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1556 chain
->real_img_size_in_bytes
= file
->size
;
1557 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1558 chain
->boot_catalog
= boot_catlog
;
1560 if (!ventoy_is_efi_os())
1562 grub_file_seek(file
, boot_catlog
* 2048);
1563 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1566 /* part 3: image chunk */
1567 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1568 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1569 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1571 if (ventoy_compatible
)
1576 /* part 4: override chunk */
1577 if (override_count
> 0)
1579 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1580 chain
->override_chunk_num
= override_count
;
1581 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1584 /* part 5: virt chunk */
1585 if (virt_chunk_count
> 0)
1587 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1588 chain
->virt_chunk_num
= virt_chunk_count
;
1589 ventoy_linux_fill_virt_data(isosize
, chain
);
1592 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);