1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <grub/types.h>
21 #include <grub/misc.h>
25 #include <grub/disk.h>
26 #include <grub/device.h>
27 #include <grub/term.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/normal.h>
31 #include <grub/extcmd.h>
32 #include <grub/datetime.h>
33 #include <grub/i18n.h>
35 #include <grub/time.h>
36 #include <grub/ventoy.h>
37 #include "ventoy_def.h"
39 GRUB_MOD_LICENSE ("GPLv3+");
41 char * ventoy_get_line(char *start
)
48 while (*start
&& *start
!= '\n')
64 static initrd_info
* ventoy_find_initrd_by_name(initrd_info
*list
, const char *name
)
66 initrd_info
*node
= list
;
70 if (grub_strcmp(node
->name
, name
) == 0)
80 grub_err_t
ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
82 initrd_info
*node
= g_initrd_img_list
;
96 g_initrd_img_list
= NULL
;
97 g_initrd_img_tail
= NULL
;
98 g_initrd_img_count
= 0;
99 g_valid_initrd_count
= 0;
101 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
104 grub_err_t
ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
107 initrd_info
*node
= g_initrd_img_list
;
113 grub_printf("###################\n");
114 grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count
);
118 grub_printf("%s ", node
->size
> 0 ? "*" : " ");
119 grub_printf("%02u %s offset:%llu size:%llu \n", i
++, node
->name
, (unsigned long long)node
->offset
,
120 (unsigned long long)node
->size
);
124 grub_printf("###################\n");
126 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
129 static void ventoy_parse_directory(char *path
, char *dir
, int buflen
)
134 pos
= grub_strstr(path
, ")");
140 end
= grub_snprintf(dir
, buflen
, "%s", pos
+ 1);
152 static grub_err_t
ventoy_isolinux_initrd_collect(grub_file_t file
, const char *prefix
)
160 char *nextline
= NULL
;
161 initrd_info
*img
= NULL
;
163 prefixlen
= grub_strlen(prefix
);
165 buf
= grub_zalloc(file
->size
+ 2);
171 grub_file_read(file
, buf
, file
->size
);
173 for (start
= buf
; start
; start
= nextline
)
175 nextline
= ventoy_get_line(start
);
177 while (ventoy_isspace(*start
))
182 offset
= 7; // strlen("initrd=") or "INITRD " or "initrd "
183 pos
= grub_strstr(start
, "initrd=");
188 if (grub_strncmp(start
, "INITRD", 6) != 0 && grub_strncmp(start
, "initrd", 6) != 0)
190 if (grub_strstr(start
, "xen") &&
191 ((pos
= grub_strstr(start
, "--- /install.img")) != NULL
||
192 (pos
= grub_strstr(start
, "--- initrd.img")) != NULL
195 offset
= 4; // "--- "
209 img
= grub_zalloc(sizeof(initrd_info
));
217 grub_strcpy(img
->name
, prefix
);
221 while (i
< 255 && (0 == ventoy_is_word_end(*pos
)))
223 img
->name
[i
++] = *pos
++;
226 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
232 if (g_initrd_img_list
)
234 img
->prev
= g_initrd_img_tail
;
235 g_initrd_img_tail
->next
= img
;
239 g_initrd_img_list
= img
;
242 g_initrd_img_tail
= img
;
243 g_initrd_img_count
++;
258 return GRUB_ERR_NONE
;
261 static int ventoy_isolinux_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
263 grub_file_t file
= NULL
;
264 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
268 if (NULL
== grub_strstr(filename
, ".cfg") && NULL
== grub_strstr(filename
, ".CFG"))
273 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
275 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", ctx
->path_prefix
, filename
);
281 ventoy_isolinux_initrd_collect(file
, ctx
->dir_prefix
);
282 grub_file_close(file
);
287 grub_err_t
ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
290 grub_device_t dev
= NULL
;
291 char *device_name
= NULL
;
292 ventoy_initrd_ctx ctx
;
298 device_name
= grub_file_get_device_name(args
[0]);
304 dev
= grub_device_open(device_name
);
310 fs
= grub_fs_probe(dev
);
316 debug("isolinux initrd collect %s\n", args
[0]);
318 ventoy_parse_directory(args
[0], directory
, sizeof(directory
) - 1);
319 ctx
.path_prefix
= args
[0];
320 ctx
.dir_prefix
= (argc
> 1) ? args
[1] : directory
;
322 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx
.path_prefix
, ctx
.dir_prefix
);
324 fs
->fs_dir(dev
, directory
, ventoy_isolinux_initrd_hook
, &ctx
);
327 check_free(device_name
, grub_free
);
328 check_free(dev
, grub_device_close
);
330 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
333 static grub_err_t
ventoy_grub_cfg_initrd_collect(const char *fileName
)
339 grub_file_t file
= NULL
;
342 char *nextline
= NULL
;
343 initrd_info
*img
= NULL
;
345 debug("grub initrd collect %s\n", fileName
);
347 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
353 buf
= grub_zalloc(file
->size
+ 2);
356 grub_file_close(file
);
360 grub_file_read(file
, buf
, file
->size
);
362 for (start
= buf
; start
; start
= nextline
)
364 nextline
= ventoy_get_line(start
);
366 while (ventoy_isspace(*start
))
371 if (grub_strncmp(start
, "initrd", 6) != 0)
377 while (*start
&& (!ventoy_isspace(*start
)))
382 while (ventoy_isspace(*start
))
395 img
= grub_zalloc(sizeof(initrd_info
));
402 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
404 img
->name
[i
] = *start
++;
405 if (img
->name
[i
] == '$')
413 len
= (int)grub_strlen(img
->name
);
414 if (len
> 2 && img
->name
[len
- 1] == '"')
416 img
->name
[len
- 1] = 0;
418 debug("Remove quotation <%s>\n", img
->name
);
421 if (dollar
== 1 || ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
427 if (g_initrd_img_list
)
429 img
->prev
= g_initrd_img_tail
;
430 g_initrd_img_tail
->next
= img
;
434 g_initrd_img_list
= img
;
437 g_initrd_img_tail
= img
;
438 g_initrd_img_count
++;
441 if (*start
== ' ' || *start
== '\t')
443 while (ventoy_isspace(*start
))
456 grub_file_close(file
);
458 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
461 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
464 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
468 debug("ventoy_grub_initrd_hook %s\n", filename
);
470 if (NULL
== grub_strstr(filename
, ".cfg") &&
471 NULL
== grub_strstr(filename
, ".CFG") &&
472 NULL
== grub_strstr(filename
, ".conf"))
477 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
479 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
480 ventoy_grub_cfg_initrd_collect(filePath
);
485 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
488 grub_device_t dev
= NULL
;
489 char *device_name
= NULL
;
490 ventoy_initrd_ctx ctx
;
500 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
502 if (grub_strcmp(args
[0], "file") == 0)
504 return ventoy_grub_cfg_initrd_collect(args
[1]);
507 device_name
= grub_file_get_device_name(args
[1]);
510 debug("failed to get device name %s\n", args
[1]);
514 dev
= grub_device_open(device_name
);
517 debug("failed to open device %s\n", device_name
);
521 fs
= grub_fs_probe(dev
);
524 debug("failed to probe fs %d\n", grub_errno
);
528 ctx
.dir_prefix
= args
[1];
529 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
532 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
536 ctx
.path_prefix
= args
[1];
539 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
541 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
544 check_free(device_name
, grub_free
);
545 check_free(dev
, grub_device_close
);
548 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
551 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
553 initrd_info
*img
= NULL
;
558 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
560 img
= grub_zalloc(sizeof(initrd_info
));
566 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
567 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
569 debug("%s is already exist\n", args
[0]);
574 if (g_initrd_img_list
)
576 img
->prev
= g_initrd_img_tail
;
577 g_initrd_img_tail
->next
= img
;
581 g_initrd_img_list
= img
;
584 g_initrd_img_tail
= img
;
585 g_initrd_img_count
++;
588 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
591 static int ventoy_cpio_newc_get_int(char *value
)
595 grub_memcpy(buf
, value
, 8);
596 return (int)grub_strtoul(buf
, NULL
, 16);
599 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
605 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
607 for (i
= 0; i
< buflen
; i
++)
614 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
618 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
622 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
626 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
627 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
629 namelen
= grub_strlen(name
) + 1;
630 headlen
= sizeof(cpio_newc_header
) + namelen
;
631 headlen
= ventoy_align(headlen
, 4);
633 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
634 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
636 grub_memcpy(cpio
->c_magic
, "070701", 6);
637 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
638 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
639 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
640 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
641 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
642 grub_memcpy(cpio
+ 1, name
, namelen
);
646 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
652 static grub_uint32_t
ventoy_linux_get_virt_chunk_count(void)
654 grub_uint32_t count
= g_valid_initrd_count
;
656 if (g_conf_replace_offset
> 0)
664 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
668 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
670 if (g_conf_replace_offset
> 0)
672 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
;
678 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
682 grub_uint64_t sector
;
683 grub_uint32_t offset
;
684 grub_uint32_t cpio_secs
;
685 grub_uint32_t initrd_secs
;
687 ventoy_virt_chunk
*cur
;
690 override
= (char *)chain
+ chain
->virt_chunk_offset
;
691 sector
= (isosize
+ 2047) / 2048;
692 cpio_secs
= g_ventoy_cpio_size
/ 2048;
694 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
695 cur
= (ventoy_virt_chunk
*)override
;
697 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
704 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
706 cur
->mem_sector_start
= sector
;
707 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
708 cur
->mem_sector_offset
= offset
;
709 cur
->remap_sector_start
= cur
->mem_sector_end
;
710 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
711 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
713 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
715 grub_memset(name
, 0, 16);
716 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
718 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
719 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
721 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
723 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
725 offset
+= g_ventoy_cpio_size
;
726 sector
+= cpio_secs
+ initrd_secs
;
730 if (g_conf_replace_offset
> 0)
732 cpio_secs
= g_conf_replace_new_len_align
/ 2048;
734 cur
->mem_sector_start
= sector
;
735 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
736 cur
->mem_sector_offset
= offset
;
737 cur
->remap_sector_start
= 0;
738 cur
->remap_sector_end
= 0;
739 cur
->org_sector_start
= 0;
741 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
, g_conf_replace_new_len
);
743 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
;
745 offset
+= g_conf_replace_new_len_align
;
753 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
755 grub_uint32_t count
= g_valid_initrd_count
;
757 if (g_conf_replace_offset
> 0)
762 if (g_svd_replace_offset
> 0)
770 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
772 int count
= g_valid_initrd_count
;
774 if (g_conf_replace_offset
> 0)
779 if (g_svd_replace_offset
> 0)
784 return sizeof(ventoy_override_chunk
) * count
;
787 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
791 grub_uint32_t newlen
;
792 grub_uint64_t sector
;
793 ventoy_override_chunk
*cur
;
794 ventoy_iso9660_override
*dirent
;
795 ventoy_udf_override
*udf
;
797 sector
= (isosize
+ 2047) / 2048;
799 cur
= (ventoy_override_chunk
*)override
;
800 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
807 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
811 newlen
+= 4 - mod
; /* cpio must align with 4 */
814 if (node
->iso_type
== 0)
816 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
818 node
->override_length
= sizeof(ventoy_iso9660_override
);
819 dirent
->first_sector
= (grub_uint32_t
)sector
;
820 dirent
->size
= newlen
;
821 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
822 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
824 sector
+= (dirent
->size
+ 2047) / 2048;
828 udf
= (ventoy_udf_override
*)node
->override_data
;
830 node
->override_length
= sizeof(ventoy_udf_override
);
831 udf
->length
= newlen
;
832 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
834 sector
+= (udf
->length
+ 2047) / 2048;
837 cur
->img_offset
= node
->override_offset
;
838 cur
->override_size
= node
->override_length
;
839 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
843 if (g_conf_replace_offset
> 0)
845 cur
->img_offset
= g_conf_replace_offset
;
846 cur
->override_size
= sizeof(ventoy_iso9660_override
);
848 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
);
850 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
851 dirent
->first_sector
= (grub_uint32_t
)sector
;
852 dirent
->size
= newlen
;
853 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
854 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
856 sector
+= (dirent
->size
+ 2047) / 2048;
860 if (g_svd_replace_offset
> 0)
862 cur
->img_offset
= g_svd_replace_offset
;
863 cur
->override_size
= 1;
864 cur
->override_data
[0] = 0xFF;
871 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
881 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
882 grub_env_set(args
[0], buf
);
885 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
888 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
898 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
899 grub_env_set(args
[0], buf
);
902 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
905 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
913 debug("ventoy_linux_locate_initrd %d\n", filt
);
915 g_valid_initrd_count
= 0;
917 if (grub_env_get("INITRD_NO_SIZE_FILT"))
922 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
924 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
930 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
932 /* initrd file too small */
934 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
935 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
938 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
940 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
941 grub_file_close(file
);
947 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
950 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
952 grub_file_read(file
, &data
, 1); // just read for hook trigger
953 node
->offset
= grub_iso9660_get_last_read_pos(file
);
960 node
->size
= file
->size
;
961 g_valid_initrd_count
++;
963 grub_file_close(file
);
968 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
972 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
976 initrd_info
*node
= NULL
;
987 if (g_initrd_img_count
== 1)
989 ventoy_set_env(args
[0], "0");
990 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
993 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1000 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1006 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1007 ventoy_set_env(args
[0], buf
);
1011 debug("main initrd index:%d\n", index
);
1013 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1016 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1024 ventoy_linux_locate_initrd(1, &sizefilt
);
1026 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1028 ventoy_linux_locate_initrd(0, &sizefilt
);
1031 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1034 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1042 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1044 name
= (char *)(head
+ 1);
1045 while (name
[0] && count
< 2)
1047 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1049 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1052 else if (grub_strcmp(name
, filepath
) == 0)
1054 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1058 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1059 offset
= sizeof(cpio_newc_header
) + namelen
;
1060 offset
= ventoy_align(offset
, 4);
1061 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1062 offset
= ventoy_align(offset
, 4);
1064 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1065 name
= (char *)(head
+ 1);
1072 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1078 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1079 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1083 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1092 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1095 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1098 for (i
= 0; i
< 10; i
++)
1101 grub_file_seek(file
, (17 + i
) * 2048);
1102 grub_file_read(file
, buf
, 16);
1104 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1106 debug("Find SVD at VD %d\n", i
);
1107 g_svd_replace_offset
= (17 + i
) * 2048;
1114 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1117 grub_file_close(file
);
1119 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1122 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1127 char *template_file
= NULL
;
1128 char *template_buf
= NULL
;
1129 char *persistent_buf
= NULL
;
1130 char *injection_buf
= NULL
;
1131 dud
*dudnode
= NULL
;
1133 const char *injection_file
= NULL
;
1134 grub_uint8_t
*buf
= NULL
;
1136 grub_uint32_t headlen
;
1137 grub_uint32_t initrd_head_len
;
1138 grub_uint32_t padlen
;
1139 grub_uint32_t img_chunk_size
;
1140 grub_uint32_t template_size
= 0;
1141 grub_uint32_t persistent_size
= 0;
1142 grub_uint32_t injection_size
= 0;
1143 grub_uint32_t dud_size
= 0;
1145 grub_file_t archfile
;
1146 grub_file_t tmpfile
;
1147 ventoy_img_chunk_list chunk_list
;
1154 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1157 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1159 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1162 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1164 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1167 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1170 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1173 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1174 grub_file_close(file
);
1177 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1179 if (g_ventoy_cpio_buf
)
1181 grub_free(g_ventoy_cpio_buf
);
1182 g_ventoy_cpio_buf
= NULL
;
1183 g_ventoy_cpio_size
= 0;
1186 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1187 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1189 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1190 persistent_buf
= (char *)(chunk_list
.chunk
);
1193 template_file
= ventoy_plugin_get_cur_install_template(args
[1]);
1196 debug("auto install template: <%s>\n", template_file
);
1197 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], template_file
);
1200 debug("auto install script size %d\n", (int)tmpfile
->size
);
1201 template_size
= tmpfile
->size
;
1202 template_buf
= grub_malloc(template_size
);
1205 grub_file_read(tmpfile
, template_buf
, template_size
);
1208 grub_file_close(tmpfile
);
1212 debug("Failed to open install script %s%s\n", args
[2], template_file
);
1217 debug("auto install script skipped or not configed %s\n", args
[1]);
1220 injection_file
= ventoy_plugin_get_injection(args
[1]);
1223 debug("injection archive: <%s>\n", injection_file
);
1224 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1227 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1228 injection_size
= tmpfile
->size
;
1229 injection_buf
= grub_malloc(injection_size
);
1232 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1235 grub_file_close(tmpfile
);
1239 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1244 debug("injection not configed %s\n", args
[1]);
1247 dudnode
= ventoy_plugin_find_dud(args
[1]);
1250 debug("dud file: <%d>\n", dudnode
->dudnum
);
1251 ventoy_plugin_load_dud(dudnode
, args
[2]);
1252 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1254 if (dudnode
->files
[i
].size
> 0)
1256 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1262 debug("dud not configed %s\n", args
[1]);
1265 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1266 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1267 if (NULL
== g_ventoy_cpio_buf
)
1269 grub_file_close(file
);
1270 grub_file_close(archfile
);
1271 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1274 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1275 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1276 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1281 grub_file_read(archfile
, buf
, archfile
->size
);
1282 buf
+= (archfile
->size
- 4);
1283 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1288 /* get initrd head len */
1289 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1291 /* step1: insert image chunk data to cpio */
1292 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1293 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1297 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1298 buf
+= headlen
+ ventoy_align(template_size
, 4);
1301 if (persistent_size
> 0 && persistent_buf
)
1303 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1304 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1306 grub_free(persistent_buf
);
1307 persistent_buf
= NULL
;
1310 if (injection_size
> 0 && injection_buf
)
1312 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1313 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1315 grub_free(injection_buf
);
1316 injection_buf
= NULL
;
1321 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1323 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1324 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1325 dud_size
= dudnode
->files
[i
].size
;
1326 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1327 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1331 /* step2: insert os param to cpio */
1332 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1333 padlen
= sizeof(ventoy_os_param
);
1334 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1335 mod
= g_ventoy_cpio_size
% 2048;
1338 g_ventoy_cpio_size
+= 2048 - mod
;
1339 padlen
+= 2048 - mod
;
1342 /* update os param data size, the data will be updated before chain boot */
1343 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1344 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1346 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1347 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1348 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1350 grub_file_close(file
);
1351 grub_file_close(archfile
);
1353 if (grub_strcmp(args
[3], "busybox=64") == 0)
1355 debug("cpio busybox proc %s\n", args
[3]);
1356 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1358 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1360 debug("cpio busybox proc %s\n", args
[3]);
1361 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1363 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1365 debug("cpio busybox proc %s\n", args
[3]);
1366 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1369 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1372 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1379 grub_uint8_t
*bufend
;
1380 cpio_newc_header
*head
;
1383 const grub_uint8_t trailler
[124] = {
1384 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1385 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1386 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1387 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1388 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1389 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1390 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1391 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1397 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1403 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1404 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1406 grub_file_close(file
);
1408 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1409 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1411 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1412 mod
= bufsize
% 512;
1415 grub_memset(bufend
, 0, 512 - mod
);
1416 bufsize
+= 512 - mod
;
1419 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1421 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1422 name
= (char *)(head
+ 1);
1424 while (grub_strcmp(name
, "TRAILER!!!"))
1426 if (grub_strcmp(name
, "init") == 0)
1428 grub_memcpy(name
, "xxxx", 4);
1430 else if (grub_strcmp(name
, "linuxrc") == 0)
1432 grub_memcpy(name
, "vtoyxrc", 7);
1434 else if (grub_strcmp(name
, "sbin") == 0)
1436 grub_memcpy(name
, "vtoy", 4);
1438 else if (grub_strcmp(name
, "sbin/init") == 0)
1440 grub_memcpy(name
, "vtoy/vtoy", 9);
1443 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1444 offset
= sizeof(cpio_newc_header
) + namelen
;
1445 offset
= ventoy_align(offset
, 4);
1446 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1447 offset
= ventoy_align(offset
, 4);
1449 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1450 name
= (char *)(head
+ 1);
1454 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1455 ventoy_set_env("ventoy_cpio_addr", value
);
1456 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1457 ventoy_set_env("ventoy_cpio_size", value
);
1459 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1463 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1465 int ventoy_compatible
= 0;
1466 grub_uint32_t size
= 0;
1467 grub_uint64_t isosize
= 0;
1468 grub_uint32_t boot_catlog
= 0;
1469 grub_uint32_t img_chunk_size
= 0;
1470 grub_uint32_t override_count
= 0;
1471 grub_uint32_t override_size
= 0;
1472 grub_uint32_t virt_chunk_count
= 0;
1473 grub_uint32_t virt_chunk_size
= 0;
1476 const char *pLastChain
= NULL
;
1477 const char *compatible
;
1478 ventoy_chain_head
*chain
;
1484 compatible
= grub_env_get("ventoy_compatible");
1485 if (compatible
&& compatible
[0] == 'Y')
1487 ventoy_compatible
= 1;
1490 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1492 grub_printf("ventoy not ready\n");
1496 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1502 isosize
= file
->size
;
1504 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1507 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1509 grub_env_set("LoadIsoEfiDriver", "on");
1514 if (ventoy_is_efi_os())
1516 grub_env_set("LoadIsoEfiDriver", "on");
1520 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1524 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1526 override_count
= ventoy_linux_get_override_chunk_count();
1527 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1529 if (ventoy_compatible
)
1531 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1535 override_size
= ventoy_linux_get_override_chunk_size();
1536 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1537 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1540 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1543 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1546 debug("free last chain memory %p\n", chain
);
1551 chain
= grub_malloc(size
);
1554 grub_printf("Failed to alloc chain memory size %u\n", size
);
1555 grub_file_close(file
);
1559 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1560 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1561 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1562 grub_env_set("vtoy_chain_mem_size", envbuf
);
1564 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1566 /* part 1: os parameter */
1567 g_ventoy_chain_type
= ventoy_chain_linux
;
1568 ventoy_fill_os_param(file
, &(chain
->os_param
));
1570 /* part 2: chain head */
1571 disk
= file
->device
->disk
;
1572 chain
->disk_drive
= disk
->id
;
1573 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1574 chain
->real_img_size_in_bytes
= file
->size
;
1575 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1576 chain
->boot_catalog
= boot_catlog
;
1578 if (!ventoy_is_efi_os())
1580 grub_file_seek(file
, boot_catlog
* 2048);
1581 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1584 /* part 3: image chunk */
1585 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1586 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1587 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1589 if (ventoy_compatible
)
1594 /* part 4: override chunk */
1595 if (override_count
> 0)
1597 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1598 chain
->override_chunk_num
= override_count
;
1599 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1602 /* part 5: virt chunk */
1603 if (virt_chunk_count
> 0)
1605 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1606 chain
->virt_chunk_num
= virt_chunk_count
;
1607 ventoy_linux_fill_virt_data(isosize
, chain
);
1610 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);