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 #define VTOY_APPEND_EXT_SIZE 4096
42 static int g_append_ext_sector
= 0;
44 char * ventoy_get_line(char *start
)
51 while (*start
&& *start
!= '\n')
67 static initrd_info
* ventoy_find_initrd_by_name(initrd_info
*list
, const char *name
)
69 initrd_info
*node
= list
;
73 if (grub_strcmp(node
->name
, name
) == 0)
83 grub_err_t
ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
85 initrd_info
*node
= g_initrd_img_list
;
99 g_initrd_img_list
= NULL
;
100 g_initrd_img_tail
= NULL
;
101 g_initrd_img_count
= 0;
102 g_valid_initrd_count
= 0;
104 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
107 grub_err_t
ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
110 initrd_info
*node
= g_initrd_img_list
;
116 grub_printf("###################\n");
117 grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count
);
121 grub_printf("%s ", node
->size
> 0 ? "*" : " ");
122 grub_printf("%02u %s offset:%llu size:%llu \n", i
++, node
->name
, (unsigned long long)node
->offset
,
123 (unsigned long long)node
->size
);
127 grub_printf("###################\n");
129 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
132 static void ventoy_parse_directory(char *path
, char *dir
, int buflen
)
137 pos
= grub_strstr(path
, ")");
143 end
= grub_snprintf(dir
, buflen
, "%s", pos
+ 1);
155 static grub_err_t
ventoy_isolinux_initrd_collect(grub_file_t file
, const char *prefix
)
163 char *nextline
= NULL
;
164 initrd_info
*img
= NULL
;
166 prefixlen
= grub_strlen(prefix
);
168 buf
= grub_zalloc(file
->size
+ 2);
174 grub_file_read(file
, buf
, file
->size
);
176 for (start
= buf
; start
; start
= nextline
)
178 nextline
= ventoy_get_line(start
);
180 while (ventoy_isspace(*start
))
185 offset
= 7; // strlen("initrd=") or "INITRD " or "initrd "
186 pos
= grub_strstr(start
, "initrd=");
191 if (grub_strncmp(start
, "INITRD", 6) != 0 && grub_strncmp(start
, "initrd", 6) != 0)
193 if (grub_strstr(start
, "xen") &&
194 ((pos
= grub_strstr(start
, "--- /install.img")) != NULL
||
195 (pos
= grub_strstr(start
, "--- initrd.img")) != NULL
198 offset
= 4; // "--- "
212 img
= grub_zalloc(sizeof(initrd_info
));
220 grub_strcpy(img
->name
, prefix
);
224 while (i
< 255 && (0 == ventoy_is_word_end(*pos
)))
226 img
->name
[i
++] = *pos
++;
229 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
235 if (g_initrd_img_list
)
237 img
->prev
= g_initrd_img_tail
;
238 g_initrd_img_tail
->next
= img
;
242 g_initrd_img_list
= img
;
245 g_initrd_img_tail
= img
;
246 g_initrd_img_count
++;
261 return GRUB_ERR_NONE
;
264 static int ventoy_isolinux_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
266 grub_file_t file
= NULL
;
267 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
271 if (NULL
== grub_strstr(filename
, ".cfg") && NULL
== grub_strstr(filename
, ".CFG"))
276 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
278 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", ctx
->path_prefix
, filename
);
284 ventoy_isolinux_initrd_collect(file
, ctx
->dir_prefix
);
285 grub_file_close(file
);
290 grub_err_t
ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
293 grub_device_t dev
= NULL
;
294 char *device_name
= NULL
;
295 ventoy_initrd_ctx ctx
;
301 device_name
= grub_file_get_device_name(args
[0]);
307 dev
= grub_device_open(device_name
);
313 fs
= grub_fs_probe(dev
);
319 debug("isolinux initrd collect %s\n", args
[0]);
321 ventoy_parse_directory(args
[0], directory
, sizeof(directory
) - 1);
322 ctx
.path_prefix
= args
[0];
323 ctx
.dir_prefix
= (argc
> 1) ? args
[1] : directory
;
325 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx
.path_prefix
, ctx
.dir_prefix
);
327 fs
->fs_dir(dev
, directory
, ventoy_isolinux_initrd_hook
, &ctx
);
330 check_free(device_name
, grub_free
);
331 check_free(dev
, grub_device_close
);
333 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
336 static grub_err_t
ventoy_grub_cfg_initrd_collect(const char *fileName
)
342 grub_file_t file
= NULL
;
345 char *nextline
= NULL
;
346 initrd_info
*img
= NULL
;
348 debug("grub initrd collect %s\n", fileName
);
350 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
356 buf
= grub_zalloc(file
->size
+ 2);
359 grub_file_close(file
);
363 grub_file_read(file
, buf
, file
->size
);
365 for (start
= buf
; start
; start
= nextline
)
367 nextline
= ventoy_get_line(start
);
369 while (ventoy_isspace(*start
))
374 if (grub_strncmp(start
, "initrd", 6) != 0)
380 while (*start
&& (!ventoy_isspace(*start
)))
385 while (ventoy_isspace(*start
))
398 img
= grub_zalloc(sizeof(initrd_info
));
405 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
407 img
->name
[i
] = *start
++;
408 if (img
->name
[i
] == '$')
416 len
= (int)grub_strlen(img
->name
);
417 if (len
> 2 && img
->name
[len
- 1] == '"')
419 img
->name
[len
- 1] = 0;
421 debug("Remove quotation <%s>\n", img
->name
);
424 if (dollar
== 1 || ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
430 if (g_initrd_img_list
)
432 img
->prev
= g_initrd_img_tail
;
433 g_initrd_img_tail
->next
= img
;
437 g_initrd_img_list
= img
;
440 g_initrd_img_tail
= img
;
441 g_initrd_img_count
++;
444 if (*start
== ' ' || *start
== '\t')
446 while (ventoy_isspace(*start
))
459 grub_file_close(file
);
461 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
464 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
467 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
471 debug("ventoy_grub_initrd_hook %s\n", filename
);
473 if (NULL
== grub_strstr(filename
, ".cfg") &&
474 NULL
== grub_strstr(filename
, ".CFG") &&
475 NULL
== grub_strstr(filename
, ".conf"))
480 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
482 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
483 ventoy_grub_cfg_initrd_collect(filePath
);
488 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
491 grub_device_t dev
= NULL
;
492 char *device_name
= NULL
;
493 ventoy_initrd_ctx ctx
;
503 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
505 if (grub_strcmp(args
[0], "file") == 0)
507 return ventoy_grub_cfg_initrd_collect(args
[1]);
510 device_name
= grub_file_get_device_name(args
[1]);
513 debug("failed to get device name %s\n", args
[1]);
517 dev
= grub_device_open(device_name
);
520 debug("failed to open device %s\n", device_name
);
524 fs
= grub_fs_probe(dev
);
527 debug("failed to probe fs %d\n", grub_errno
);
531 ctx
.dir_prefix
= args
[1];
532 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
535 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
539 ctx
.path_prefix
= args
[1];
542 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
544 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
547 check_free(device_name
, grub_free
);
548 check_free(dev
, grub_device_close
);
551 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
554 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
556 initrd_info
*img
= NULL
;
561 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
563 img
= grub_zalloc(sizeof(initrd_info
));
569 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
570 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
572 debug("%s is already exist\n", args
[0]);
577 if (g_initrd_img_list
)
579 img
->prev
= g_initrd_img_tail
;
580 g_initrd_img_tail
->next
= img
;
584 g_initrd_img_list
= img
;
587 g_initrd_img_tail
= img
;
588 g_initrd_img_count
++;
591 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
594 static int ventoy_cpio_newc_get_int(char *value
)
598 grub_memcpy(buf
, value
, 8);
599 return (int)grub_strtoul(buf
, NULL
, 16);
602 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
608 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
610 for (i
= 0; i
< buflen
; i
++)
617 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
621 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
625 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
629 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
630 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
632 namelen
= grub_strlen(name
) + 1;
633 headlen
= sizeof(cpio_newc_header
) + namelen
;
634 headlen
= ventoy_align(headlen
, 4);
636 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
637 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
639 grub_memcpy(cpio
->c_magic
, "070701", 6);
640 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
641 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
642 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
643 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
644 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
645 grub_memcpy(cpio
+ 1, name
, namelen
);
649 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
655 static grub_uint32_t
ventoy_linux_get_virt_chunk_count(void)
658 grub_uint32_t count
= g_valid_initrd_count
;
660 if (g_conf_replace_count
> 0)
662 for (i
= 0; i
< g_conf_replace_count
; i
++)
664 if (g_conf_replace_offset
[i
] > 0)
671 if (g_append_ext_sector
> 0)
679 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
684 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
686 if (g_conf_replace_count
> 0)
688 for (i
= 0; i
< g_conf_replace_count
; i
++)
690 if (g_conf_replace_offset
[i
] > 0)
692 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
[i
];
697 if (g_append_ext_sector
> 0)
699 size
+= sizeof(ventoy_virt_chunk
) + VTOY_APPEND_EXT_SIZE
;
705 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
711 grub_uint64_t sector
;
712 grub_uint32_t offset
;
713 grub_uint32_t cpio_secs
;
714 grub_uint32_t initrd_secs
;
716 ventoy_virt_chunk
*cur
;
717 ventoy_grub_param_file_replace
*replace
= NULL
;
720 override
= (char *)chain
+ chain
->virt_chunk_offset
;
721 sector
= (isosize
+ 2047) / 2048;
722 cpio_secs
= g_ventoy_cpio_size
/ 2048;
724 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
725 cur
= (ventoy_virt_chunk
*)override
;
727 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
734 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
736 cur
->mem_sector_start
= sector
;
737 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
738 cur
->mem_sector_offset
= offset
;
739 cur
->remap_sector_start
= cur
->mem_sector_end
;
740 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
741 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
743 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
745 grub_memset(name
, 0, 16);
746 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
748 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
749 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
751 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
753 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
755 offset
+= g_ventoy_cpio_size
;
756 sector
+= cpio_secs
+ initrd_secs
;
761 /* Lenovo EasyStartup need an addional sector for boundary check */
762 if (g_append_ext_sector
> 0)
764 cpio_secs
= VTOY_APPEND_EXT_SIZE
/ 2048;
766 cur
->mem_sector_start
= sector
;
767 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
768 cur
->mem_sector_offset
= offset
;
769 cur
->remap_sector_start
= 0;
770 cur
->remap_sector_end
= 0;
771 cur
->org_sector_start
= 0;
773 grub_memset(override
+ offset
, 0, VTOY_APPEND_EXT_SIZE
);
775 chain
->virt_img_size_in_bytes
+= VTOY_APPEND_EXT_SIZE
;
777 offset
+= VTOY_APPEND_EXT_SIZE
;
783 if (g_conf_replace_count
> 0)
785 for (i
= 0; i
< g_conf_replace_count
; i
++)
787 if (g_conf_replace_offset
[i
] > 0)
789 cpio_secs
= g_conf_replace_new_len_align
[i
] / 2048;
791 cur
->mem_sector_start
= sector
;
792 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
793 cur
->mem_sector_offset
= offset
;
794 cur
->remap_sector_start
= 0;
795 cur
->remap_sector_end
= 0;
796 cur
->org_sector_start
= 0;
798 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
[i
], g_conf_replace_new_len
[i
]);
800 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
[i
];
802 replace
= g_grub_param
->img_replace
+ i
;
803 if (replace
->magic
== GRUB_IMG_REPLACE_MAGIC
)
805 replace
->new_file_virtual_id
= virtid
;
808 offset
+= g_conf_replace_new_len_align
[i
];
819 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
822 grub_uint32_t count
= g_valid_initrd_count
;
824 if (g_conf_replace_count
> 0)
826 for (i
= 0; i
< g_conf_replace_count
; i
++)
828 if (g_conf_replace_offset
[i
] > 0)
835 if (g_svd_replace_offset
> 0)
843 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
846 int count
= g_valid_initrd_count
;
848 if (g_conf_replace_count
> 0)
850 for (i
= 0; i
< g_conf_replace_count
; i
++)
852 if (g_conf_replace_offset
[i
] > 0)
859 if (g_svd_replace_offset
> 0)
864 return sizeof(ventoy_override_chunk
) * count
;
867 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
872 grub_uint32_t newlen
;
873 grub_uint64_t sector
;
874 ventoy_override_chunk
*cur
;
875 ventoy_iso9660_override
*dirent
;
876 ventoy_udf_override
*udf
;
878 sector
= (isosize
+ 2047) / 2048;
880 cur
= (ventoy_override_chunk
*)override
;
881 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
888 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
892 newlen
+= 4 - mod
; /* cpio must align with 4 */
895 if (node
->iso_type
== 0)
897 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
899 node
->override_length
= sizeof(ventoy_iso9660_override
);
900 dirent
->first_sector
= (grub_uint32_t
)sector
;
901 dirent
->size
= newlen
;
902 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
903 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
905 sector
+= (dirent
->size
+ 2047) / 2048;
909 udf
= (ventoy_udf_override
*)node
->override_data
;
911 node
->override_length
= sizeof(ventoy_udf_override
);
912 udf
->length
= newlen
;
913 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
915 sector
+= (udf
->length
+ 2047) / 2048;
918 cur
->img_offset
= node
->override_offset
;
919 cur
->override_size
= node
->override_length
;
920 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
924 if (g_conf_replace_count
> 0)
926 for (i
= 0; i
< g_conf_replace_count
; i
++)
928 if (g_conf_replace_offset
[i
] > 0)
930 cur
->img_offset
= g_conf_replace_offset
[i
];
931 cur
->override_size
= sizeof(ventoy_iso9660_override
);
933 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
[i
]);
935 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
936 dirent
->first_sector
= (grub_uint32_t
)sector
;
937 dirent
->size
= newlen
;
938 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
939 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
941 sector
+= (dirent
->size
+ 2047) / 2048;
947 if (g_svd_replace_offset
> 0)
949 cur
->img_offset
= g_svd_replace_offset
;
950 cur
->override_size
= 1;
951 cur
->override_data
[0] = 0xFF;
958 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
968 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
969 grub_env_set(args
[0], buf
);
972 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
975 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
985 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
986 grub_env_set(args
[0], buf
);
989 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
992 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
1000 debug("ventoy_linux_locate_initrd %d\n", filt
);
1002 g_valid_initrd_count
= 0;
1004 if (grub_env_get("INITRD_NO_SIZE_FILT"))
1009 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1011 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
1017 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
1019 /* initrd file too small */
1021 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
1022 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
1025 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
1027 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
1028 grub_file_close(file
);
1035 if (file
->size
<= VTOY_SIZE_1MB
&& grub_strcmp(node
->name
, "/boot/hdt.img") == 0)
1040 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
1043 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
1045 grub_file_read(file
, &data
, 1); // just read for hook trigger
1046 node
->offset
= grub_iso9660_get_last_read_pos(file
);
1053 node
->size
= file
->size
;
1054 g_valid_initrd_count
++;
1056 grub_file_close(file
);
1059 *filtcnt
= sizefilt
;
1061 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1065 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1069 initrd_info
*node
= NULL
;
1080 if (g_initrd_img_count
== 1)
1082 ventoy_set_env(args
[0], "0");
1083 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1086 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1088 if (node
->size
<= 0)
1093 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1099 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1100 ventoy_set_env(args
[0], buf
);
1104 debug("main initrd index:%d\n", index
);
1106 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1109 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1117 ventoy_linux_locate_initrd(1, &sizefilt
);
1119 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1121 ventoy_linux_locate_initrd(0, &sizefilt
);
1124 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1127 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1135 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1137 name
= (char *)(head
+ 1);
1138 while (name
[0] && count
< 2)
1140 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1142 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1145 else if (grub_strcmp(name
, filepath
) == 0)
1147 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1151 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1152 offset
= sizeof(cpio_newc_header
) + namelen
;
1153 offset
= ventoy_align(offset
, 4);
1154 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1155 offset
= ventoy_align(offset
, 4);
1157 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1158 name
= (char *)(head
+ 1);
1165 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1171 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1172 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1176 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1185 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1188 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1191 for (i
= 0; i
< 10; i
++)
1194 grub_file_seek(file
, (17 + i
) * 2048);
1195 grub_file_read(file
, buf
, 16);
1197 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1199 debug("Find SVD at VD %d\n", i
);
1200 g_svd_replace_offset
= (17 + i
) * 2048;
1207 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1210 grub_file_close(file
);
1212 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1215 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1221 if (args
[0][0] == '1')
1223 g_append_ext_sector
= 1;
1227 g_append_ext_sector
= 0;
1230 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1233 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1238 char *template_file
= NULL
;
1239 char *template_buf
= NULL
;
1240 char *persistent_buf
= NULL
;
1241 char *injection_buf
= NULL
;
1242 dud
*dudnode
= NULL
;
1244 const char *injection_file
= NULL
;
1245 grub_uint8_t
*buf
= NULL
;
1247 grub_uint32_t headlen
;
1248 grub_uint32_t initrd_head_len
;
1249 grub_uint32_t padlen
;
1250 grub_uint32_t img_chunk_size
;
1251 grub_uint32_t template_size
= 0;
1252 grub_uint32_t persistent_size
= 0;
1253 grub_uint32_t injection_size
= 0;
1254 grub_uint32_t dud_size
= 0;
1256 grub_file_t archfile
;
1257 grub_file_t tmpfile
;
1258 install_template
*template_node
= NULL
;
1259 ventoy_img_chunk_list chunk_list
;
1266 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1269 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1271 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1274 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1276 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1279 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1282 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1285 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1286 grub_file_close(file
);
1289 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1291 if (g_ventoy_cpio_buf
)
1293 grub_free(g_ventoy_cpio_buf
);
1294 g_ventoy_cpio_buf
= NULL
;
1295 g_ventoy_cpio_size
= 0;
1298 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1299 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1301 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1302 persistent_buf
= (char *)(chunk_list
.chunk
);
1305 template_file
= ventoy_plugin_get_cur_install_template(args
[1], &template_node
);
1308 debug("auto install template: <%s> <addr:%p> <len:%d>\n",
1309 template_file
, template_node
->filebuf
, template_node
->filelen
);
1311 template_size
= template_node
->filelen
;
1312 template_buf
= grub_malloc(template_size
);
1315 grub_memcpy(template_buf
, template_node
->filebuf
, template_size
);
1320 debug("auto install script skipped or not configed %s\n", args
[1]);
1323 injection_file
= ventoy_plugin_get_injection(args
[1]);
1326 debug("injection archive: <%s>\n", injection_file
);
1327 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1330 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1331 injection_size
= tmpfile
->size
;
1332 injection_buf
= grub_malloc(injection_size
);
1335 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1338 grub_file_close(tmpfile
);
1342 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1347 debug("injection not configed %s\n", args
[1]);
1350 dudnode
= ventoy_plugin_find_dud(args
[1]);
1353 debug("dud file: <%d>\n", dudnode
->dudnum
);
1354 ventoy_plugin_load_dud(dudnode
, args
[2]);
1355 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1357 if (dudnode
->files
[i
].size
> 0)
1359 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1365 debug("dud not configed %s\n", args
[1]);
1368 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1369 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1370 if (NULL
== g_ventoy_cpio_buf
)
1372 grub_file_close(file
);
1373 grub_file_close(archfile
);
1374 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1377 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1378 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1379 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1384 grub_file_read(archfile
, buf
, archfile
->size
);
1385 buf
+= (archfile
->size
- 4);
1386 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1391 /* get initrd head len */
1392 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1394 /* step1: insert image chunk data to cpio */
1395 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1396 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1400 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1401 buf
+= headlen
+ ventoy_align(template_size
, 4);
1402 grub_check_free(template_buf
);
1405 if (persistent_size
> 0 && persistent_buf
)
1407 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1408 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1409 grub_check_free(persistent_buf
);
1412 if (injection_size
> 0 && injection_buf
)
1414 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1415 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1417 grub_free(injection_buf
);
1418 injection_buf
= NULL
;
1423 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1425 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1426 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1427 dud_size
= dudnode
->files
[i
].size
;
1428 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1429 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1433 /* step2: insert os param to cpio */
1434 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1435 padlen
= sizeof(ventoy_os_param
);
1436 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1437 mod
= g_ventoy_cpio_size
% 2048;
1440 g_ventoy_cpio_size
+= 2048 - mod
;
1441 padlen
+= 2048 - mod
;
1444 /* update os param data size, the data will be updated before chain boot */
1445 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1446 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1448 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1449 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1450 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1452 grub_file_close(file
);
1453 grub_file_close(archfile
);
1455 if (grub_strcmp(args
[3], "busybox=64") == 0)
1457 debug("cpio busybox proc %s\n", args
[3]);
1458 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1460 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1462 debug("cpio busybox proc %s\n", args
[3]);
1463 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1465 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1467 debug("cpio busybox proc %s\n", args
[3]);
1468 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1471 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1474 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1481 grub_uint8_t
*bufend
;
1482 cpio_newc_header
*head
;
1485 const grub_uint8_t trailler
[124] = {
1486 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1487 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1488 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1489 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1490 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1491 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1492 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1493 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1499 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1505 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1506 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1508 grub_file_close(file
);
1510 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1511 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1513 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1514 mod
= bufsize
% 512;
1517 grub_memset(bufend
, 0, 512 - mod
);
1518 bufsize
+= 512 - mod
;
1521 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1523 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1524 name
= (char *)(head
+ 1);
1526 while (grub_strcmp(name
, "TRAILER!!!"))
1528 if (grub_strcmp(name
, "init") == 0)
1530 grub_memcpy(name
, "xxxx", 4);
1532 else if (grub_strcmp(name
, "linuxrc") == 0)
1534 grub_memcpy(name
, "vtoyxrc", 7);
1536 else if (grub_strcmp(name
, "sbin") == 0)
1538 grub_memcpy(name
, "vtoy", 4);
1540 else if (grub_strcmp(name
, "sbin/init") == 0)
1542 grub_memcpy(name
, "vtoy/vtoy", 9);
1545 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1546 offset
= sizeof(cpio_newc_header
) + namelen
;
1547 offset
= ventoy_align(offset
, 4);
1548 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1549 offset
= ventoy_align(offset
, 4);
1551 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1552 name
= (char *)(head
+ 1);
1556 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1557 ventoy_set_env("ventoy_cpio_addr", value
);
1558 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1559 ventoy_set_env("ventoy_cpio_size", value
);
1561 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1564 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1567 int ventoy_compatible
= 0;
1568 grub_uint32_t size
= 0;
1569 grub_uint64_t isosize
= 0;
1570 grub_uint32_t boot_catlog
= 0;
1571 grub_uint32_t img_chunk_size
= 0;
1572 grub_uint32_t override_count
= 0;
1573 grub_uint32_t override_size
= 0;
1574 grub_uint32_t virt_chunk_count
= 0;
1575 grub_uint32_t virt_chunk_size
= 0;
1578 const char *pLastChain
= NULL
;
1579 const char *compatible
;
1580 ventoy_chain_head
*chain
;
1586 compatible
= grub_env_get("ventoy_compatible");
1587 if (compatible
&& compatible
[0] == 'Y')
1589 ventoy_compatible
= 1;
1592 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1594 grub_printf("ventoy not ready\n");
1598 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1604 isosize
= file
->size
;
1606 len
= (int)grub_strlen(args
[0]);
1607 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1609 debug("boot catlog %u for img file\n", boot_catlog
);
1613 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1616 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1618 grub_env_set("LoadIsoEfiDriver", "on");
1623 if (ventoy_is_efi_os())
1625 grub_env_set("LoadIsoEfiDriver", "on");
1629 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1634 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1636 override_count
= ventoy_linux_get_override_chunk_count();
1637 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1639 if (ventoy_compatible
)
1641 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1645 override_size
= ventoy_linux_get_override_chunk_size();
1646 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1647 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1650 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1653 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1656 debug("free last chain memory %p\n", chain
);
1661 chain
= ventoy_alloc_chain(size
);
1664 grub_printf("Failed to alloc chain linux memory size %u\n", size
);
1665 grub_file_close(file
);
1669 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1670 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1671 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1672 grub_env_set("vtoy_chain_mem_size", envbuf
);
1674 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1676 /* part 1: os parameter */
1677 g_ventoy_chain_type
= ventoy_chain_linux
;
1678 ventoy_fill_os_param(file
, &(chain
->os_param
));
1680 /* part 2: chain head */
1681 disk
= file
->device
->disk
;
1682 chain
->disk_drive
= disk
->id
;
1683 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1684 chain
->real_img_size_in_bytes
= file
->size
;
1685 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1686 chain
->boot_catalog
= boot_catlog
;
1688 if (!ventoy_is_efi_os())
1690 grub_file_seek(file
, boot_catlog
* 2048);
1691 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1694 /* part 3: image chunk */
1695 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1696 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1697 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1699 if (ventoy_compatible
)
1704 /* part 4: override chunk */
1705 if (override_count
> 0)
1707 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1708 chain
->override_chunk_num
= override_count
;
1709 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1712 /* part 5: virt chunk */
1713 if (virt_chunk_count
> 0)
1715 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1716 chain
->virt_chunk_num
= virt_chunk_count
;
1717 ventoy_linux_fill_virt_data(isosize
, chain
);
1720 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);