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
);
981 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
984 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
986 grub_file_read(file
, &data
, 1); // just read for hook trigger
987 node
->offset
= grub_iso9660_get_last_read_pos(file
);
994 node
->size
= file
->size
;
995 g_valid_initrd_count
++;
997 grub_file_close(file
);
1000 *filtcnt
= sizefilt
;
1002 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1006 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1010 initrd_info
*node
= NULL
;
1021 if (g_initrd_img_count
== 1)
1023 ventoy_set_env(args
[0], "0");
1024 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1027 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1029 if (node
->size
<= 0)
1034 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1040 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1041 ventoy_set_env(args
[0], buf
);
1045 debug("main initrd index:%d\n", index
);
1047 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1050 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1058 ventoy_linux_locate_initrd(1, &sizefilt
);
1060 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1062 ventoy_linux_locate_initrd(0, &sizefilt
);
1065 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1068 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1076 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1078 name
= (char *)(head
+ 1);
1079 while (name
[0] && count
< 2)
1081 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1083 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1086 else if (grub_strcmp(name
, filepath
) == 0)
1088 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1092 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1093 offset
= sizeof(cpio_newc_header
) + namelen
;
1094 offset
= ventoy_align(offset
, 4);
1095 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1096 offset
= ventoy_align(offset
, 4);
1098 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1099 name
= (char *)(head
+ 1);
1106 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1112 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1113 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1117 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1126 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1129 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1132 for (i
= 0; i
< 10; i
++)
1135 grub_file_seek(file
, (17 + i
) * 2048);
1136 grub_file_read(file
, buf
, 16);
1138 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1140 debug("Find SVD at VD %d\n", i
);
1141 g_svd_replace_offset
= (17 + i
) * 2048;
1148 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1151 grub_file_close(file
);
1153 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1156 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1162 if (args
[0][0] == '1')
1164 g_append_ext_sector
= 1;
1168 g_append_ext_sector
= 0;
1171 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1174 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1179 char *template_file
= NULL
;
1180 char *template_buf
= NULL
;
1181 char *persistent_buf
= NULL
;
1182 char *injection_buf
= NULL
;
1183 dud
*dudnode
= NULL
;
1185 const char *injection_file
= NULL
;
1186 grub_uint8_t
*buf
= NULL
;
1188 grub_uint32_t headlen
;
1189 grub_uint32_t initrd_head_len
;
1190 grub_uint32_t padlen
;
1191 grub_uint32_t img_chunk_size
;
1192 grub_uint32_t template_size
= 0;
1193 grub_uint32_t persistent_size
= 0;
1194 grub_uint32_t injection_size
= 0;
1195 grub_uint32_t dud_size
= 0;
1197 grub_file_t archfile
;
1198 grub_file_t tmpfile
;
1199 ventoy_img_chunk_list chunk_list
;
1206 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1209 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1211 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1214 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1216 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1219 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1222 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1225 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1226 grub_file_close(file
);
1229 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1231 if (g_ventoy_cpio_buf
)
1233 grub_free(g_ventoy_cpio_buf
);
1234 g_ventoy_cpio_buf
= NULL
;
1235 g_ventoy_cpio_size
= 0;
1238 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1239 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1241 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1242 persistent_buf
= (char *)(chunk_list
.chunk
);
1245 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1248 debug("auto install template: <%s>\n", template_file
);
1249 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1252 debug("auto install script size %d\n", (int)tmpfile
->size
);
1253 template_size
= tmpfile
->size
;
1254 template_buf
= grub_malloc(template_size
);
1257 grub_file_read(tmpfile
, template_buf
, template_size
);
1260 grub_file_close(tmpfile
);
1264 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1269 debug("auto install script skipped or not configed %s\n", args
[1]);
1272 injection_file
= ventoy_plugin_get_injection(args
[1]);
1275 debug("injection archive: <%s>\n", injection_file
);
1276 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1279 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1280 injection_size
= tmpfile
->size
;
1281 injection_buf
= grub_malloc(injection_size
);
1284 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1287 grub_file_close(tmpfile
);
1291 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1296 debug("injection not configed %s\n", args
[1]);
1299 dudnode
= ventoy_plugin_find_dud(args
[1]);
1302 debug("dud file: <%d>\n", dudnode
->dudnum
);
1303 ventoy_plugin_load_dud(dudnode
, args
[2]);
1304 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1306 if (dudnode
->files
[i
].size
> 0)
1308 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1314 debug("dud not configed %s\n", args
[1]);
1317 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1318 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1319 if (NULL
== g_ventoy_cpio_buf
)
1321 grub_file_close(file
);
1322 grub_file_close(archfile
);
1323 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1326 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1327 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1328 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1333 grub_file_read(archfile
, buf
, archfile
->size
);
1334 buf
+= (archfile
->size
- 4);
1335 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1340 /* get initrd head len */
1341 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1343 /* step1: insert image chunk data to cpio */
1344 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1345 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1349 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1350 buf
+= headlen
+ ventoy_align(template_size
, 4);
1353 if (persistent_size
> 0 && persistent_buf
)
1355 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1356 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1358 grub_free(persistent_buf
);
1359 persistent_buf
= NULL
;
1362 if (injection_size
> 0 && injection_buf
)
1364 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1365 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1367 grub_free(injection_buf
);
1368 injection_buf
= NULL
;
1373 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1375 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1376 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1377 dud_size
= dudnode
->files
[i
].size
;
1378 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1379 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1383 /* step2: insert os param to cpio */
1384 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1385 padlen
= sizeof(ventoy_os_param
);
1386 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1387 mod
= g_ventoy_cpio_size
% 2048;
1390 g_ventoy_cpio_size
+= 2048 - mod
;
1391 padlen
+= 2048 - mod
;
1394 /* update os param data size, the data will be updated before chain boot */
1395 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1396 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1398 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1399 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1400 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1402 grub_file_close(file
);
1403 grub_file_close(archfile
);
1405 if (grub_strcmp(args
[3], "busybox=64") == 0)
1407 debug("cpio busybox proc %s\n", args
[3]);
1408 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1410 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1412 debug("cpio busybox proc %s\n", args
[3]);
1413 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1415 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1417 debug("cpio busybox proc %s\n", args
[3]);
1418 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1421 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1424 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1431 grub_uint8_t
*bufend
;
1432 cpio_newc_header
*head
;
1435 const grub_uint8_t trailler
[124] = {
1436 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1437 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1438 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1439 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1440 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1441 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1442 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1443 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1449 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1455 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1456 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1458 grub_file_close(file
);
1460 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1461 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1463 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1464 mod
= bufsize
% 512;
1467 grub_memset(bufend
, 0, 512 - mod
);
1468 bufsize
+= 512 - mod
;
1471 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1473 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1474 name
= (char *)(head
+ 1);
1476 while (grub_strcmp(name
, "TRAILER!!!"))
1478 if (grub_strcmp(name
, "init") == 0)
1480 grub_memcpy(name
, "xxxx", 4);
1482 else if (grub_strcmp(name
, "linuxrc") == 0)
1484 grub_memcpy(name
, "vtoyxrc", 7);
1486 else if (grub_strcmp(name
, "sbin") == 0)
1488 grub_memcpy(name
, "vtoy", 4);
1490 else if (grub_strcmp(name
, "sbin/init") == 0)
1492 grub_memcpy(name
, "vtoy/vtoy", 9);
1495 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1496 offset
= sizeof(cpio_newc_header
) + namelen
;
1497 offset
= ventoy_align(offset
, 4);
1498 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1499 offset
= ventoy_align(offset
, 4);
1501 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1502 name
= (char *)(head
+ 1);
1506 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1507 ventoy_set_env("ventoy_cpio_addr", value
);
1508 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1509 ventoy_set_env("ventoy_cpio_size", value
);
1511 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1514 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1517 int ventoy_compatible
= 0;
1518 grub_uint32_t size
= 0;
1519 grub_uint64_t isosize
= 0;
1520 grub_uint32_t boot_catlog
= 0;
1521 grub_uint32_t img_chunk_size
= 0;
1522 grub_uint32_t override_count
= 0;
1523 grub_uint32_t override_size
= 0;
1524 grub_uint32_t virt_chunk_count
= 0;
1525 grub_uint32_t virt_chunk_size
= 0;
1528 const char *pLastChain
= NULL
;
1529 const char *compatible
;
1530 ventoy_chain_head
*chain
;
1536 compatible
= grub_env_get("ventoy_compatible");
1537 if (compatible
&& compatible
[0] == 'Y')
1539 ventoy_compatible
= 1;
1542 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1544 grub_printf("ventoy not ready\n");
1548 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1554 isosize
= file
->size
;
1556 len
= (int)grub_strlen(args
[0]);
1557 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1559 debug("boot catlog %u for img file\n", boot_catlog
);
1563 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1566 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1568 grub_env_set("LoadIsoEfiDriver", "on");
1573 if (ventoy_is_efi_os())
1575 grub_env_set("LoadIsoEfiDriver", "on");
1579 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1584 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1586 override_count
= ventoy_linux_get_override_chunk_count();
1587 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1589 if (ventoy_compatible
)
1591 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1595 override_size
= ventoy_linux_get_override_chunk_size();
1596 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1597 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1600 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1603 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1606 debug("free last chain memory %p\n", chain
);
1611 chain
= grub_malloc(size
);
1614 grub_printf("Failed to alloc chain memory size %u\n", size
);
1615 grub_file_close(file
);
1619 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1620 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1621 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1622 grub_env_set("vtoy_chain_mem_size", envbuf
);
1624 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1626 /* part 1: os parameter */
1627 g_ventoy_chain_type
= ventoy_chain_linux
;
1628 ventoy_fill_os_param(file
, &(chain
->os_param
));
1630 /* part 2: chain head */
1631 disk
= file
->device
->disk
;
1632 chain
->disk_drive
= disk
->id
;
1633 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1634 chain
->real_img_size_in_bytes
= file
->size
;
1635 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1636 chain
->boot_catalog
= boot_catlog
;
1638 if (!ventoy_is_efi_os())
1640 grub_file_seek(file
, boot_catlog
* 2048);
1641 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1644 /* part 3: image chunk */
1645 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1646 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1647 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1649 if (ventoy_compatible
)
1654 /* part 4: override chunk */
1655 if (override_count
> 0)
1657 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1658 chain
->override_chunk_num
= override_count
;
1659 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1662 /* part 5: virt chunk */
1663 if (virt_chunk_count
> 0)
1665 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1666 chain
->virt_chunk_num
= virt_chunk_count
;
1667 ventoy_linux_fill_virt_data(isosize
, chain
);
1670 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);