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
)
695 grub_uint64_t sector
;
696 grub_uint32_t offset
;
697 grub_uint32_t cpio_secs
;
698 grub_uint32_t initrd_secs
;
700 ventoy_virt_chunk
*cur
;
703 override
= (char *)chain
+ chain
->virt_chunk_offset
;
704 sector
= (isosize
+ 2047) / 2048;
705 cpio_secs
= g_ventoy_cpio_size
/ 2048;
707 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
708 cur
= (ventoy_virt_chunk
*)override
;
710 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
717 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
719 cur
->mem_sector_start
= sector
;
720 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
721 cur
->mem_sector_offset
= offset
;
722 cur
->remap_sector_start
= cur
->mem_sector_end
;
723 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
724 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
726 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
728 grub_memset(name
, 0, 16);
729 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
731 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
732 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
734 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
736 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
738 offset
+= g_ventoy_cpio_size
;
739 sector
+= cpio_secs
+ initrd_secs
;
743 /* Lenovo EasyStartup need an addional sector for boundary check */
744 if (g_append_ext_sector
> 0)
746 cpio_secs
= VTOY_APPEND_EXT_SIZE
/ 2048;
748 cur
->mem_sector_start
= sector
;
749 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
750 cur
->mem_sector_offset
= offset
;
751 cur
->remap_sector_start
= 0;
752 cur
->remap_sector_end
= 0;
753 cur
->org_sector_start
= 0;
755 grub_memset(override
+ offset
, 0, VTOY_APPEND_EXT_SIZE
);
757 chain
->virt_img_size_in_bytes
+= VTOY_APPEND_EXT_SIZE
;
759 offset
+= VTOY_APPEND_EXT_SIZE
;
764 if (g_conf_replace_offset
> 0)
766 cpio_secs
= g_conf_replace_new_len_align
/ 2048;
768 cur
->mem_sector_start
= sector
;
769 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
770 cur
->mem_sector_offset
= offset
;
771 cur
->remap_sector_start
= 0;
772 cur
->remap_sector_end
= 0;
773 cur
->org_sector_start
= 0;
775 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
, g_conf_replace_new_len
);
777 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
;
779 offset
+= g_conf_replace_new_len_align
;
787 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
789 grub_uint32_t count
= g_valid_initrd_count
;
791 if (g_conf_replace_offset
> 0)
796 if (g_svd_replace_offset
> 0)
804 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
806 int count
= g_valid_initrd_count
;
808 if (g_conf_replace_offset
> 0)
813 if (g_svd_replace_offset
> 0)
818 return sizeof(ventoy_override_chunk
) * count
;
821 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
825 grub_uint32_t newlen
;
826 grub_uint64_t sector
;
827 ventoy_override_chunk
*cur
;
828 ventoy_iso9660_override
*dirent
;
829 ventoy_udf_override
*udf
;
831 sector
= (isosize
+ 2047) / 2048;
833 cur
= (ventoy_override_chunk
*)override
;
834 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
841 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
845 newlen
+= 4 - mod
; /* cpio must align with 4 */
848 if (node
->iso_type
== 0)
850 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
852 node
->override_length
= sizeof(ventoy_iso9660_override
);
853 dirent
->first_sector
= (grub_uint32_t
)sector
;
854 dirent
->size
= newlen
;
855 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
856 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
858 sector
+= (dirent
->size
+ 2047) / 2048;
862 udf
= (ventoy_udf_override
*)node
->override_data
;
864 node
->override_length
= sizeof(ventoy_udf_override
);
865 udf
->length
= newlen
;
866 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
868 sector
+= (udf
->length
+ 2047) / 2048;
871 cur
->img_offset
= node
->override_offset
;
872 cur
->override_size
= node
->override_length
;
873 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
877 if (g_conf_replace_offset
> 0)
879 cur
->img_offset
= g_conf_replace_offset
;
880 cur
->override_size
= sizeof(ventoy_iso9660_override
);
882 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
);
884 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
885 dirent
->first_sector
= (grub_uint32_t
)sector
;
886 dirent
->size
= newlen
;
887 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
888 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
890 sector
+= (dirent
->size
+ 2047) / 2048;
894 if (g_svd_replace_offset
> 0)
896 cur
->img_offset
= g_svd_replace_offset
;
897 cur
->override_size
= 1;
898 cur
->override_data
[0] = 0xFF;
905 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
915 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
916 grub_env_set(args
[0], buf
);
919 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
922 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
932 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
933 grub_env_set(args
[0], buf
);
936 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
939 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
947 debug("ventoy_linux_locate_initrd %d\n", filt
);
949 g_valid_initrd_count
= 0;
951 if (grub_env_get("INITRD_NO_SIZE_FILT"))
956 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
958 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
964 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
966 /* initrd file too small */
968 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
969 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
972 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
974 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
975 grub_file_close(file
);
982 if (file
->size
<= VTOY_SIZE_1MB
&& grub_strcmp(node
->name
, "/boot/hdt.img") == 0)
987 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
990 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
992 grub_file_read(file
, &data
, 1); // just read for hook trigger
993 node
->offset
= grub_iso9660_get_last_read_pos(file
);
1000 node
->size
= file
->size
;
1001 g_valid_initrd_count
++;
1003 grub_file_close(file
);
1006 *filtcnt
= sizefilt
;
1008 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1012 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1016 initrd_info
*node
= NULL
;
1027 if (g_initrd_img_count
== 1)
1029 ventoy_set_env(args
[0], "0");
1030 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1033 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1035 if (node
->size
<= 0)
1040 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1046 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1047 ventoy_set_env(args
[0], buf
);
1051 debug("main initrd index:%d\n", index
);
1053 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1056 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1064 ventoy_linux_locate_initrd(1, &sizefilt
);
1066 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1068 ventoy_linux_locate_initrd(0, &sizefilt
);
1071 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1074 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1082 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1084 name
= (char *)(head
+ 1);
1085 while (name
[0] && count
< 2)
1087 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1089 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1092 else if (grub_strcmp(name
, filepath
) == 0)
1094 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1098 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1099 offset
= sizeof(cpio_newc_header
) + namelen
;
1100 offset
= ventoy_align(offset
, 4);
1101 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1102 offset
= ventoy_align(offset
, 4);
1104 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1105 name
= (char *)(head
+ 1);
1112 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1118 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1119 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1123 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1132 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1135 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1138 for (i
= 0; i
< 10; i
++)
1141 grub_file_seek(file
, (17 + i
) * 2048);
1142 grub_file_read(file
, buf
, 16);
1144 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1146 debug("Find SVD at VD %d\n", i
);
1147 g_svd_replace_offset
= (17 + i
) * 2048;
1154 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1157 grub_file_close(file
);
1159 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1162 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1168 if (args
[0][0] == '1')
1170 g_append_ext_sector
= 1;
1174 g_append_ext_sector
= 0;
1177 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1180 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1185 char *template_file
= NULL
;
1186 char *template_buf
= NULL
;
1187 char *persistent_buf
= NULL
;
1188 char *injection_buf
= NULL
;
1189 dud
*dudnode
= NULL
;
1191 const char *injection_file
= NULL
;
1192 grub_uint8_t
*buf
= NULL
;
1194 grub_uint32_t headlen
;
1195 grub_uint32_t initrd_head_len
;
1196 grub_uint32_t padlen
;
1197 grub_uint32_t img_chunk_size
;
1198 grub_uint32_t template_size
= 0;
1199 grub_uint32_t persistent_size
= 0;
1200 grub_uint32_t injection_size
= 0;
1201 grub_uint32_t dud_size
= 0;
1203 grub_file_t archfile
;
1204 grub_file_t tmpfile
;
1205 ventoy_img_chunk_list chunk_list
;
1212 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1215 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1217 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1220 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1222 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1225 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1228 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1231 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1232 grub_file_close(file
);
1235 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1237 if (g_ventoy_cpio_buf
)
1239 grub_free(g_ventoy_cpio_buf
);
1240 g_ventoy_cpio_buf
= NULL
;
1241 g_ventoy_cpio_size
= 0;
1244 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1245 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1247 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1248 persistent_buf
= (char *)(chunk_list
.chunk
);
1251 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1254 debug("auto install template: <%s>\n", template_file
);
1255 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1258 debug("auto install script size %d\n", (int)tmpfile
->size
);
1259 template_size
= tmpfile
->size
;
1260 template_buf
= grub_malloc(template_size
);
1263 grub_file_read(tmpfile
, template_buf
, template_size
);
1266 grub_file_close(tmpfile
);
1270 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1275 debug("auto install script skipped or not configed %s\n", args
[1]);
1278 injection_file
= ventoy_plugin_get_injection(args
[1]);
1281 debug("injection archive: <%s>\n", injection_file
);
1282 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1285 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1286 injection_size
= tmpfile
->size
;
1287 injection_buf
= grub_malloc(injection_size
);
1290 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1293 grub_file_close(tmpfile
);
1297 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1302 debug("injection not configed %s\n", args
[1]);
1305 dudnode
= ventoy_plugin_find_dud(args
[1]);
1308 debug("dud file: <%d>\n", dudnode
->dudnum
);
1309 ventoy_plugin_load_dud(dudnode
, args
[2]);
1310 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1312 if (dudnode
->files
[i
].size
> 0)
1314 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1320 debug("dud not configed %s\n", args
[1]);
1323 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1324 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1325 if (NULL
== g_ventoy_cpio_buf
)
1327 grub_file_close(file
);
1328 grub_file_close(archfile
);
1329 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1332 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1333 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1334 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1339 grub_file_read(archfile
, buf
, archfile
->size
);
1340 buf
+= (archfile
->size
- 4);
1341 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1346 /* get initrd head len */
1347 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1349 /* step1: insert image chunk data to cpio */
1350 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1351 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1355 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1356 buf
+= headlen
+ ventoy_align(template_size
, 4);
1359 if (persistent_size
> 0 && persistent_buf
)
1361 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1362 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1364 grub_free(persistent_buf
);
1365 persistent_buf
= NULL
;
1368 if (injection_size
> 0 && injection_buf
)
1370 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1371 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1373 grub_free(injection_buf
);
1374 injection_buf
= NULL
;
1379 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1381 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1382 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1383 dud_size
= dudnode
->files
[i
].size
;
1384 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1385 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1389 /* step2: insert os param to cpio */
1390 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1391 padlen
= sizeof(ventoy_os_param
);
1392 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1393 mod
= g_ventoy_cpio_size
% 2048;
1396 g_ventoy_cpio_size
+= 2048 - mod
;
1397 padlen
+= 2048 - mod
;
1400 /* update os param data size, the data will be updated before chain boot */
1401 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1402 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1404 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1405 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1406 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1408 grub_file_close(file
);
1409 grub_file_close(archfile
);
1411 if (grub_strcmp(args
[3], "busybox=64") == 0)
1413 debug("cpio busybox proc %s\n", args
[3]);
1414 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1416 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1418 debug("cpio busybox proc %s\n", args
[3]);
1419 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1421 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1423 debug("cpio busybox proc %s\n", args
[3]);
1424 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1427 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1430 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1437 grub_uint8_t
*bufend
;
1438 cpio_newc_header
*head
;
1441 const grub_uint8_t trailler
[124] = {
1442 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1443 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1444 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1445 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1446 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1447 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1448 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1449 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1455 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1461 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1462 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1464 grub_file_close(file
);
1466 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1467 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1469 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1470 mod
= bufsize
% 512;
1473 grub_memset(bufend
, 0, 512 - mod
);
1474 bufsize
+= 512 - mod
;
1477 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1479 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1480 name
= (char *)(head
+ 1);
1482 while (grub_strcmp(name
, "TRAILER!!!"))
1484 if (grub_strcmp(name
, "init") == 0)
1486 grub_memcpy(name
, "xxxx", 4);
1488 else if (grub_strcmp(name
, "linuxrc") == 0)
1490 grub_memcpy(name
, "vtoyxrc", 7);
1492 else if (grub_strcmp(name
, "sbin") == 0)
1494 grub_memcpy(name
, "vtoy", 4);
1496 else if (grub_strcmp(name
, "sbin/init") == 0)
1498 grub_memcpy(name
, "vtoy/vtoy", 9);
1501 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1502 offset
= sizeof(cpio_newc_header
) + namelen
;
1503 offset
= ventoy_align(offset
, 4);
1504 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1505 offset
= ventoy_align(offset
, 4);
1507 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1508 name
= (char *)(head
+ 1);
1512 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1513 ventoy_set_env("ventoy_cpio_addr", value
);
1514 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1515 ventoy_set_env("ventoy_cpio_size", value
);
1517 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1520 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1523 int ventoy_compatible
= 0;
1524 grub_uint32_t size
= 0;
1525 grub_uint64_t isosize
= 0;
1526 grub_uint32_t boot_catlog
= 0;
1527 grub_uint32_t img_chunk_size
= 0;
1528 grub_uint32_t override_count
= 0;
1529 grub_uint32_t override_size
= 0;
1530 grub_uint32_t virt_chunk_count
= 0;
1531 grub_uint32_t virt_chunk_size
= 0;
1534 const char *pLastChain
= NULL
;
1535 const char *compatible
;
1536 ventoy_chain_head
*chain
;
1542 compatible
= grub_env_get("ventoy_compatible");
1543 if (compatible
&& compatible
[0] == 'Y')
1545 ventoy_compatible
= 1;
1548 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1550 grub_printf("ventoy not ready\n");
1554 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1560 isosize
= file
->size
;
1562 len
= (int)grub_strlen(args
[0]);
1563 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1565 debug("boot catlog %u for img file\n", boot_catlog
);
1569 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1572 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1574 grub_env_set("LoadIsoEfiDriver", "on");
1579 if (ventoy_is_efi_os())
1581 grub_env_set("LoadIsoEfiDriver", "on");
1585 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1590 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1592 override_count
= ventoy_linux_get_override_chunk_count();
1593 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1595 if (ventoy_compatible
)
1597 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1601 override_size
= ventoy_linux_get_override_chunk_size();
1602 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1603 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1606 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1609 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1612 debug("free last chain memory %p\n", chain
);
1617 chain
= grub_malloc(size
);
1620 grub_printf("Failed to alloc chain memory size %u\n", size
);
1621 grub_file_close(file
);
1625 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1626 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1627 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1628 grub_env_set("vtoy_chain_mem_size", envbuf
);
1630 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1632 /* part 1: os parameter */
1633 g_ventoy_chain_type
= ventoy_chain_linux
;
1634 ventoy_fill_os_param(file
, &(chain
->os_param
));
1636 /* part 2: chain head */
1637 disk
= file
->device
->disk
;
1638 chain
->disk_drive
= disk
->id
;
1639 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1640 chain
->real_img_size_in_bytes
= file
->size
;
1641 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1642 chain
->boot_catalog
= boot_catlog
;
1644 if (!ventoy_is_efi_os())
1646 grub_file_seek(file
, boot_catlog
* 2048);
1647 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1650 /* part 3: image chunk */
1651 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1652 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1653 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1655 if (ventoy_compatible
)
1660 /* part 4: override chunk */
1661 if (override_count
> 0)
1663 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1664 chain
->override_chunk_num
= override_count
;
1665 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1668 /* part 5: virt chunk */
1669 if (virt_chunk_count
> 0)
1671 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1672 chain
->virt_chunk_num
= virt_chunk_count
;
1673 ventoy_linux_fill_virt_data(isosize
, chain
);
1676 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);