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)
657 grub_uint32_t count
= g_valid_initrd_count
;
659 if (g_conf_replace_offset
> 0)
664 if (g_append_ext_sector
> 0)
672 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
676 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
678 if (g_conf_replace_offset
> 0)
680 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
;
683 if (g_append_ext_sector
> 0)
685 size
+= sizeof(ventoy_virt_chunk
) + VTOY_APPEND_EXT_SIZE
;
691 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
696 grub_uint64_t sector
;
697 grub_uint32_t offset
;
698 grub_uint32_t cpio_secs
;
699 grub_uint32_t initrd_secs
;
701 ventoy_virt_chunk
*cur
;
704 override
= (char *)chain
+ chain
->virt_chunk_offset
;
705 sector
= (isosize
+ 2047) / 2048;
706 cpio_secs
= g_ventoy_cpio_size
/ 2048;
708 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
709 cur
= (ventoy_virt_chunk
*)override
;
711 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
718 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
720 cur
->mem_sector_start
= sector
;
721 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
722 cur
->mem_sector_offset
= offset
;
723 cur
->remap_sector_start
= cur
->mem_sector_end
;
724 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
725 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
727 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
729 grub_memset(name
, 0, 16);
730 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
732 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
733 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
735 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
737 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
739 offset
+= g_ventoy_cpio_size
;
740 sector
+= cpio_secs
+ initrd_secs
;
745 /* Lenovo EasyStartup need an addional sector for boundary check */
746 if (g_append_ext_sector
> 0)
748 cpio_secs
= VTOY_APPEND_EXT_SIZE
/ 2048;
750 cur
->mem_sector_start
= sector
;
751 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
752 cur
->mem_sector_offset
= offset
;
753 cur
->remap_sector_start
= 0;
754 cur
->remap_sector_end
= 0;
755 cur
->org_sector_start
= 0;
757 grub_memset(override
+ offset
, 0, VTOY_APPEND_EXT_SIZE
);
759 chain
->virt_img_size_in_bytes
+= VTOY_APPEND_EXT_SIZE
;
761 offset
+= VTOY_APPEND_EXT_SIZE
;
767 if (g_conf_replace_offset
> 0)
769 cpio_secs
= g_conf_replace_new_len_align
/ 2048;
771 cur
->mem_sector_start
= sector
;
772 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
773 cur
->mem_sector_offset
= offset
;
774 cur
->remap_sector_start
= 0;
775 cur
->remap_sector_end
= 0;
776 cur
->org_sector_start
= 0;
778 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
, g_conf_replace_new_len
);
780 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
;
782 if (g_grub_param
->img_replace
.magic
== GRUB_IMG_REPLACE_MAGIC
)
784 g_grub_param
->img_replace
.new_file_virtual_id
= virtid
;
787 offset
+= g_conf_replace_new_len_align
;
796 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
798 grub_uint32_t count
= g_valid_initrd_count
;
800 if (g_conf_replace_offset
> 0)
805 if (g_svd_replace_offset
> 0)
813 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
815 int count
= g_valid_initrd_count
;
817 if (g_conf_replace_offset
> 0)
822 if (g_svd_replace_offset
> 0)
827 return sizeof(ventoy_override_chunk
) * count
;
830 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
834 grub_uint32_t newlen
;
835 grub_uint64_t sector
;
836 ventoy_override_chunk
*cur
;
837 ventoy_iso9660_override
*dirent
;
838 ventoy_udf_override
*udf
;
840 sector
= (isosize
+ 2047) / 2048;
842 cur
= (ventoy_override_chunk
*)override
;
843 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
850 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
854 newlen
+= 4 - mod
; /* cpio must align with 4 */
857 if (node
->iso_type
== 0)
859 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
861 node
->override_length
= sizeof(ventoy_iso9660_override
);
862 dirent
->first_sector
= (grub_uint32_t
)sector
;
863 dirent
->size
= newlen
;
864 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
865 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
867 sector
+= (dirent
->size
+ 2047) / 2048;
871 udf
= (ventoy_udf_override
*)node
->override_data
;
873 node
->override_length
= sizeof(ventoy_udf_override
);
874 udf
->length
= newlen
;
875 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
877 sector
+= (udf
->length
+ 2047) / 2048;
880 cur
->img_offset
= node
->override_offset
;
881 cur
->override_size
= node
->override_length
;
882 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
886 if (g_conf_replace_offset
> 0)
888 cur
->img_offset
= g_conf_replace_offset
;
889 cur
->override_size
= sizeof(ventoy_iso9660_override
);
891 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
);
893 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
894 dirent
->first_sector
= (grub_uint32_t
)sector
;
895 dirent
->size
= newlen
;
896 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
897 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
899 sector
+= (dirent
->size
+ 2047) / 2048;
903 if (g_svd_replace_offset
> 0)
905 cur
->img_offset
= g_svd_replace_offset
;
906 cur
->override_size
= 1;
907 cur
->override_data
[0] = 0xFF;
914 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
924 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
925 grub_env_set(args
[0], buf
);
928 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
931 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
941 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
942 grub_env_set(args
[0], buf
);
945 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
948 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
956 debug("ventoy_linux_locate_initrd %d\n", filt
);
958 g_valid_initrd_count
= 0;
960 if (grub_env_get("INITRD_NO_SIZE_FILT"))
965 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
967 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
973 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
975 /* initrd file too small */
977 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
978 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
981 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
983 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
984 grub_file_close(file
);
991 if (file
->size
<= VTOY_SIZE_1MB
&& grub_strcmp(node
->name
, "/boot/hdt.img") == 0)
996 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
999 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
1001 grub_file_read(file
, &data
, 1); // just read for hook trigger
1002 node
->offset
= grub_iso9660_get_last_read_pos(file
);
1009 node
->size
= file
->size
;
1010 g_valid_initrd_count
++;
1012 grub_file_close(file
);
1015 *filtcnt
= sizefilt
;
1017 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1021 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1025 initrd_info
*node
= NULL
;
1036 if (g_initrd_img_count
== 1)
1038 ventoy_set_env(args
[0], "0");
1039 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1042 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1044 if (node
->size
<= 0)
1049 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1055 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1056 ventoy_set_env(args
[0], buf
);
1060 debug("main initrd index:%d\n", index
);
1062 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1065 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1073 ventoy_linux_locate_initrd(1, &sizefilt
);
1075 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1077 ventoy_linux_locate_initrd(0, &sizefilt
);
1080 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1083 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1091 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1093 name
= (char *)(head
+ 1);
1094 while (name
[0] && count
< 2)
1096 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1098 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1101 else if (grub_strcmp(name
, filepath
) == 0)
1103 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1107 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1108 offset
= sizeof(cpio_newc_header
) + namelen
;
1109 offset
= ventoy_align(offset
, 4);
1110 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1111 offset
= ventoy_align(offset
, 4);
1113 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1114 name
= (char *)(head
+ 1);
1121 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1127 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1128 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1132 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1141 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1144 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1147 for (i
= 0; i
< 10; i
++)
1150 grub_file_seek(file
, (17 + i
) * 2048);
1151 grub_file_read(file
, buf
, 16);
1153 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1155 debug("Find SVD at VD %d\n", i
);
1156 g_svd_replace_offset
= (17 + i
) * 2048;
1163 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1166 grub_file_close(file
);
1168 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1171 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1177 if (args
[0][0] == '1')
1179 g_append_ext_sector
= 1;
1183 g_append_ext_sector
= 0;
1186 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1189 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1194 char *template_file
= NULL
;
1195 char *template_buf
= NULL
;
1196 char *persistent_buf
= NULL
;
1197 char *injection_buf
= NULL
;
1198 dud
*dudnode
= NULL
;
1200 const char *injection_file
= NULL
;
1201 grub_uint8_t
*buf
= NULL
;
1203 grub_uint32_t headlen
;
1204 grub_uint32_t initrd_head_len
;
1205 grub_uint32_t padlen
;
1206 grub_uint32_t img_chunk_size
;
1207 grub_uint32_t template_size
= 0;
1208 grub_uint32_t persistent_size
= 0;
1209 grub_uint32_t injection_size
= 0;
1210 grub_uint32_t dud_size
= 0;
1212 grub_file_t archfile
;
1213 grub_file_t tmpfile
;
1214 ventoy_img_chunk_list chunk_list
;
1221 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1224 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1226 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1229 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1231 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1234 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1237 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1240 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1241 grub_file_close(file
);
1244 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1246 if (g_ventoy_cpio_buf
)
1248 grub_free(g_ventoy_cpio_buf
);
1249 g_ventoy_cpio_buf
= NULL
;
1250 g_ventoy_cpio_size
= 0;
1253 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1254 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1256 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1257 persistent_buf
= (char *)(chunk_list
.chunk
);
1260 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1263 debug("auto install template: <%s>\n", template_file
);
1264 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1267 debug("auto install script size %d\n", (int)tmpfile
->size
);
1268 template_size
= tmpfile
->size
;
1269 template_buf
= grub_malloc(template_size
);
1272 grub_file_read(tmpfile
, template_buf
, template_size
);
1275 grub_file_close(tmpfile
);
1279 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1284 debug("auto install script skipped or not configed %s\n", args
[1]);
1287 injection_file
= ventoy_plugin_get_injection(args
[1]);
1290 debug("injection archive: <%s>\n", injection_file
);
1291 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1294 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1295 injection_size
= tmpfile
->size
;
1296 injection_buf
= grub_malloc(injection_size
);
1299 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1302 grub_file_close(tmpfile
);
1306 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1311 debug("injection not configed %s\n", args
[1]);
1314 dudnode
= ventoy_plugin_find_dud(args
[1]);
1317 debug("dud file: <%d>\n", dudnode
->dudnum
);
1318 ventoy_plugin_load_dud(dudnode
, args
[2]);
1319 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1321 if (dudnode
->files
[i
].size
> 0)
1323 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1329 debug("dud not configed %s\n", args
[1]);
1332 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1333 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1334 if (NULL
== g_ventoy_cpio_buf
)
1336 grub_file_close(file
);
1337 grub_file_close(archfile
);
1338 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1341 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1342 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1343 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1348 grub_file_read(archfile
, buf
, archfile
->size
);
1349 buf
+= (archfile
->size
- 4);
1350 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1355 /* get initrd head len */
1356 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1358 /* step1: insert image chunk data to cpio */
1359 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1360 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1364 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1365 buf
+= headlen
+ ventoy_align(template_size
, 4);
1368 if (persistent_size
> 0 && persistent_buf
)
1370 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1371 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1373 grub_free(persistent_buf
);
1374 persistent_buf
= NULL
;
1377 if (injection_size
> 0 && injection_buf
)
1379 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1380 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1382 grub_free(injection_buf
);
1383 injection_buf
= NULL
;
1388 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1390 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1391 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1392 dud_size
= dudnode
->files
[i
].size
;
1393 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1394 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1398 /* step2: insert os param to cpio */
1399 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1400 padlen
= sizeof(ventoy_os_param
);
1401 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1402 mod
= g_ventoy_cpio_size
% 2048;
1405 g_ventoy_cpio_size
+= 2048 - mod
;
1406 padlen
+= 2048 - mod
;
1409 /* update os param data size, the data will be updated before chain boot */
1410 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1411 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1413 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1414 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1415 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1417 grub_file_close(file
);
1418 grub_file_close(archfile
);
1420 if (grub_strcmp(args
[3], "busybox=64") == 0)
1422 debug("cpio busybox proc %s\n", args
[3]);
1423 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1425 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1427 debug("cpio busybox proc %s\n", args
[3]);
1428 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1430 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1432 debug("cpio busybox proc %s\n", args
[3]);
1433 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1436 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1439 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1446 grub_uint8_t
*bufend
;
1447 cpio_newc_header
*head
;
1450 const grub_uint8_t trailler
[124] = {
1451 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1452 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1453 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1454 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1455 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1456 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1457 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1458 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1464 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1470 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1471 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1473 grub_file_close(file
);
1475 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1476 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1478 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1479 mod
= bufsize
% 512;
1482 grub_memset(bufend
, 0, 512 - mod
);
1483 bufsize
+= 512 - mod
;
1486 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1488 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1489 name
= (char *)(head
+ 1);
1491 while (grub_strcmp(name
, "TRAILER!!!"))
1493 if (grub_strcmp(name
, "init") == 0)
1495 grub_memcpy(name
, "xxxx", 4);
1497 else if (grub_strcmp(name
, "linuxrc") == 0)
1499 grub_memcpy(name
, "vtoyxrc", 7);
1501 else if (grub_strcmp(name
, "sbin") == 0)
1503 grub_memcpy(name
, "vtoy", 4);
1505 else if (grub_strcmp(name
, "sbin/init") == 0)
1507 grub_memcpy(name
, "vtoy/vtoy", 9);
1510 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1511 offset
= sizeof(cpio_newc_header
) + namelen
;
1512 offset
= ventoy_align(offset
, 4);
1513 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1514 offset
= ventoy_align(offset
, 4);
1516 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1517 name
= (char *)(head
+ 1);
1521 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1522 ventoy_set_env("ventoy_cpio_addr", value
);
1523 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1524 ventoy_set_env("ventoy_cpio_size", value
);
1526 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1529 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1532 int ventoy_compatible
= 0;
1533 grub_uint32_t size
= 0;
1534 grub_uint64_t isosize
= 0;
1535 grub_uint32_t boot_catlog
= 0;
1536 grub_uint32_t img_chunk_size
= 0;
1537 grub_uint32_t override_count
= 0;
1538 grub_uint32_t override_size
= 0;
1539 grub_uint32_t virt_chunk_count
= 0;
1540 grub_uint32_t virt_chunk_size
= 0;
1543 const char *pLastChain
= NULL
;
1544 const char *compatible
;
1545 ventoy_chain_head
*chain
;
1551 compatible
= grub_env_get("ventoy_compatible");
1552 if (compatible
&& compatible
[0] == 'Y')
1554 ventoy_compatible
= 1;
1557 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1559 grub_printf("ventoy not ready\n");
1563 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1569 isosize
= file
->size
;
1571 len
= (int)grub_strlen(args
[0]);
1572 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1574 debug("boot catlog %u for img file\n", boot_catlog
);
1578 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1581 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1583 grub_env_set("LoadIsoEfiDriver", "on");
1588 if (ventoy_is_efi_os())
1590 grub_env_set("LoadIsoEfiDriver", "on");
1594 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1599 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1601 override_count
= ventoy_linux_get_override_chunk_count();
1602 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1604 if (ventoy_compatible
)
1606 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1610 override_size
= ventoy_linux_get_override_chunk_size();
1611 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1612 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1615 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1618 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1621 debug("free last chain memory %p\n", chain
);
1626 chain
= grub_malloc(size
);
1629 grub_printf("Failed to alloc chain memory size %u\n", size
);
1630 grub_file_close(file
);
1634 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1635 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1636 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1637 grub_env_set("vtoy_chain_mem_size", envbuf
);
1639 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1641 /* part 1: os parameter */
1642 g_ventoy_chain_type
= ventoy_chain_linux
;
1643 ventoy_fill_os_param(file
, &(chain
->os_param
));
1645 /* part 2: chain head */
1646 disk
= file
->device
->disk
;
1647 chain
->disk_drive
= disk
->id
;
1648 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1649 chain
->real_img_size_in_bytes
= file
->size
;
1650 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1651 chain
->boot_catalog
= boot_catlog
;
1653 if (!ventoy_is_efi_os())
1655 grub_file_seek(file
, boot_catlog
* 2048);
1656 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1659 /* part 3: image chunk */
1660 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1661 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1662 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1664 if (ventoy_compatible
)
1669 /* part 4: override chunk */
1670 if (override_count
> 0)
1672 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1673 chain
->override_chunk_num
= override_count
;
1674 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1677 /* part 5: virt chunk */
1678 if (virt_chunk_count
> 0)
1680 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1681 chain
->virt_chunk_num
= virt_chunk_count
;
1682 ventoy_linux_fill_virt_data(isosize
, chain
);
1685 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);