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 int ventoy_linux_initrd_collect_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
339 initrd_info
*img
= NULL
;
345 if (grub_strncmp(filename
, "initrd", 6) == 0)
347 len
= (int)grub_strlen(filename
);
348 if (grub_strcmp(filename
+ len
- 4, ".img") == 0)
350 img
= grub_zalloc(sizeof(initrd_info
));
353 grub_snprintf(img
->name
, sizeof(img
->name
), "/boot/%s", filename
);
355 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
361 if (g_initrd_img_list
)
363 img
->prev
= g_initrd_img_tail
;
364 g_initrd_img_tail
->next
= img
;
368 g_initrd_img_list
= img
;
371 g_initrd_img_tail
= img
;
372 g_initrd_img_count
++;
382 static int ventoy_linux_collect_boot_initrds(void)
385 grub_device_t dev
= NULL
;
387 dev
= grub_device_open("loop");
390 debug("failed to open device loop\n");
394 fs
= grub_fs_probe(dev
);
397 debug("failed to probe fs %d\n", grub_errno
);
401 fs
->fs_dir(dev
, "/boot", ventoy_linux_initrd_collect_hook
, NULL
);
407 static grub_err_t
ventoy_grub_cfg_initrd_collect(const char *fileName
)
413 int initrd_dollar
= 0;
414 grub_file_t file
= NULL
;
417 char *nextline
= NULL
;
418 initrd_info
*img
= NULL
;
420 debug("grub initrd collect %s\n", fileName
);
422 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
428 buf
= grub_zalloc(file
->size
+ 2);
431 grub_file_close(file
);
435 grub_file_read(file
, buf
, file
->size
);
437 for (start
= buf
; start
; start
= nextline
)
439 nextline
= ventoy_get_line(start
);
441 while (ventoy_isspace(*start
))
446 if (grub_strncmp(start
, "initrd", 6) != 0)
452 while (*start
&& (!ventoy_isspace(*start
)))
457 while (ventoy_isspace(*start
))
470 img
= grub_zalloc(sizeof(initrd_info
));
477 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
479 img
->name
[i
] = *start
++;
480 if (img
->name
[i
] == '$')
488 len
= (int)grub_strlen(img
->name
);
489 if (len
> 2 && img
->name
[len
- 1] == '"')
491 img
->name
[len
- 1] = 0;
493 debug("Remove quotation <%s>\n", img
->name
);
496 /* special process for /boot/initrd$XXX.img */
499 if (grub_strncmp(img
->name
, "/boot/initrd$", 13) == 0)
501 len
= (int)grub_strlen(img
->name
);
502 if (grub_strcmp(img
->name
+ len
- 4, ".img") == 0)
509 if (dollar
== 1 || ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
515 if (g_initrd_img_list
)
517 img
->prev
= g_initrd_img_tail
;
518 g_initrd_img_tail
->next
= img
;
522 g_initrd_img_list
= img
;
525 g_initrd_img_tail
= img
;
526 g_initrd_img_count
++;
529 if (*start
== ' ' || *start
== '\t')
531 while (ventoy_isspace(*start
))
544 grub_file_close(file
);
546 if (initrd_dollar
> 0 && grub_strncmp(fileName
, "(loop)/", 7) == 0)
548 debug("collect initrd variable %d\n", initrd_dollar
);
549 ventoy_linux_collect_boot_initrds();
552 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
555 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
558 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
562 debug("ventoy_grub_initrd_hook %s\n", filename
);
564 if (NULL
== grub_strstr(filename
, ".cfg") &&
565 NULL
== grub_strstr(filename
, ".CFG") &&
566 NULL
== grub_strstr(filename
, ".conf"))
571 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
573 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
574 ventoy_grub_cfg_initrd_collect(filePath
);
579 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
582 grub_device_t dev
= NULL
;
583 char *device_name
= NULL
;
584 ventoy_initrd_ctx ctx
;
594 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
596 if (grub_strcmp(args
[0], "file") == 0)
598 return ventoy_grub_cfg_initrd_collect(args
[1]);
601 device_name
= grub_file_get_device_name(args
[1]);
604 debug("failed to get device name %s\n", args
[1]);
608 dev
= grub_device_open(device_name
);
611 debug("failed to open device %s\n", device_name
);
615 fs
= grub_fs_probe(dev
);
618 debug("failed to probe fs %d\n", grub_errno
);
622 ctx
.dir_prefix
= args
[1];
623 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
626 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
630 ctx
.path_prefix
= args
[1];
633 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
635 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
638 check_free(device_name
, grub_free
);
639 check_free(dev
, grub_device_close
);
642 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
645 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
647 initrd_info
*img
= NULL
;
652 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
654 img
= grub_zalloc(sizeof(initrd_info
));
660 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
661 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
663 debug("%s is already exist\n", args
[0]);
668 if (g_initrd_img_list
)
670 img
->prev
= g_initrd_img_tail
;
671 g_initrd_img_tail
->next
= img
;
675 g_initrd_img_list
= img
;
678 g_initrd_img_tail
= img
;
679 g_initrd_img_count
++;
682 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
685 static int ventoy_cpio_newc_get_int(char *value
)
689 grub_memcpy(buf
, value
, 8);
690 return (int)grub_strtoul(buf
, NULL
, 16);
693 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
699 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
701 for (i
= 0; i
< buflen
; i
++)
708 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
712 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
716 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
720 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
721 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
723 namelen
= grub_strlen(name
) + 1;
724 headlen
= sizeof(cpio_newc_header
) + namelen
;
725 headlen
= ventoy_align(headlen
, 4);
727 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
728 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
730 grub_memcpy(cpio
->c_magic
, "070701", 6);
731 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
732 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
733 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
734 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
735 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
736 grub_memcpy(cpio
+ 1, name
, namelen
);
740 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
746 static grub_uint32_t
ventoy_linux_get_virt_chunk_count(void)
749 grub_uint32_t count
= g_valid_initrd_count
;
751 if (g_conf_replace_count
> 0)
753 for (i
= 0; i
< g_conf_replace_count
; i
++)
755 if (g_conf_replace_offset
[i
] > 0)
762 if (g_append_ext_sector
> 0)
770 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
775 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
777 if (g_conf_replace_count
> 0)
779 for (i
= 0; i
< g_conf_replace_count
; i
++)
781 if (g_conf_replace_offset
[i
] > 0)
783 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
[i
];
788 if (g_append_ext_sector
> 0)
790 size
+= sizeof(ventoy_virt_chunk
) + VTOY_APPEND_EXT_SIZE
;
796 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
802 grub_uint64_t sector
;
803 grub_uint32_t offset
;
804 grub_uint32_t cpio_secs
;
805 grub_uint32_t initrd_secs
;
807 ventoy_virt_chunk
*cur
;
808 ventoy_grub_param_file_replace
*replace
= NULL
;
811 override
= (char *)chain
+ chain
->virt_chunk_offset
;
812 sector
= (isosize
+ 2047) / 2048;
813 cpio_secs
= g_ventoy_cpio_size
/ 2048;
815 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
816 cur
= (ventoy_virt_chunk
*)override
;
818 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
825 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
827 cur
->mem_sector_start
= sector
;
828 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
829 cur
->mem_sector_offset
= offset
;
830 cur
->remap_sector_start
= cur
->mem_sector_end
;
831 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
832 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
834 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
836 grub_memset(name
, 0, 16);
837 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
839 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
840 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
842 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
844 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
846 offset
+= g_ventoy_cpio_size
;
847 sector
+= cpio_secs
+ initrd_secs
;
852 /* Lenovo EasyStartup need an addional sector for boundary check */
853 if (g_append_ext_sector
> 0)
855 cpio_secs
= VTOY_APPEND_EXT_SIZE
/ 2048;
857 cur
->mem_sector_start
= sector
;
858 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
859 cur
->mem_sector_offset
= offset
;
860 cur
->remap_sector_start
= 0;
861 cur
->remap_sector_end
= 0;
862 cur
->org_sector_start
= 0;
864 grub_memset(override
+ offset
, 0, VTOY_APPEND_EXT_SIZE
);
866 chain
->virt_img_size_in_bytes
+= VTOY_APPEND_EXT_SIZE
;
868 offset
+= VTOY_APPEND_EXT_SIZE
;
874 if (g_conf_replace_count
> 0)
876 for (i
= 0; i
< g_conf_replace_count
; i
++)
878 if (g_conf_replace_offset
[i
] > 0)
880 cpio_secs
= g_conf_replace_new_len_align
[i
] / 2048;
882 cur
->mem_sector_start
= sector
;
883 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
884 cur
->mem_sector_offset
= offset
;
885 cur
->remap_sector_start
= 0;
886 cur
->remap_sector_end
= 0;
887 cur
->org_sector_start
= 0;
889 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
[i
], g_conf_replace_new_len
[i
]);
891 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
[i
];
893 replace
= g_grub_param
->img_replace
+ i
;
894 if (replace
->magic
== GRUB_IMG_REPLACE_MAGIC
)
896 replace
->new_file_virtual_id
= virtid
;
899 offset
+= g_conf_replace_new_len_align
[i
];
910 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
913 grub_uint32_t count
= g_valid_initrd_count
;
915 if (g_conf_replace_count
> 0)
917 for (i
= 0; i
< g_conf_replace_count
; i
++)
919 if (g_conf_replace_offset
[i
] > 0)
926 if (g_svd_replace_offset
> 0)
934 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
937 int count
= g_valid_initrd_count
;
939 if (g_conf_replace_count
> 0)
941 for (i
= 0; i
< g_conf_replace_count
; i
++)
943 if (g_conf_replace_offset
[i
] > 0)
950 if (g_svd_replace_offset
> 0)
955 return sizeof(ventoy_override_chunk
) * count
;
958 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
963 grub_uint32_t newlen
;
964 grub_uint64_t sector
;
965 ventoy_override_chunk
*cur
;
966 ventoy_iso9660_override
*dirent
;
967 ventoy_udf_override
*udf
;
969 sector
= (isosize
+ 2047) / 2048;
971 cur
= (ventoy_override_chunk
*)override
;
972 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
979 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
983 newlen
+= 4 - mod
; /* cpio must align with 4 */
986 if (node
->iso_type
== 0)
988 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
990 node
->override_length
= sizeof(ventoy_iso9660_override
);
991 dirent
->first_sector
= (grub_uint32_t
)sector
;
992 dirent
->size
= newlen
;
993 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
994 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
996 sector
+= (dirent
->size
+ 2047) / 2048;
1000 udf
= (ventoy_udf_override
*)node
->override_data
;
1002 node
->override_length
= sizeof(ventoy_udf_override
);
1003 udf
->length
= newlen
;
1004 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
1006 sector
+= (udf
->length
+ 2047) / 2048;
1009 cur
->img_offset
= node
->override_offset
;
1010 cur
->override_size
= node
->override_length
;
1011 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
1015 if (g_conf_replace_count
> 0)
1017 for (i
= 0; i
< g_conf_replace_count
; i
++)
1019 if (g_conf_replace_offset
[i
] > 0)
1021 cur
->img_offset
= g_conf_replace_offset
[i
];
1022 cur
->override_size
= sizeof(ventoy_iso9660_override
);
1024 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
[i
]);
1026 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
1027 dirent
->first_sector
= (grub_uint32_t
)sector
;
1028 dirent
->size
= newlen
;
1029 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1030 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1032 sector
+= (dirent
->size
+ 2047) / 2048;
1038 if (g_svd_replace_offset
> 0)
1040 cur
->img_offset
= g_svd_replace_offset
;
1041 cur
->override_size
= 1;
1042 cur
->override_data
[0] = 0xFF;
1049 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1059 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
1060 grub_env_set(args
[0], buf
);
1063 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1066 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1076 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
1077 grub_env_set(args
[0], buf
);
1080 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1083 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
1091 debug("ventoy_linux_locate_initrd %d\n", filt
);
1093 g_valid_initrd_count
= 0;
1095 if (grub_env_get("INITRD_NO_SIZE_FILT"))
1100 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1102 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
1108 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
1110 /* initrd file too small */
1112 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
1113 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
1116 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
1118 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
1119 grub_file_close(file
);
1126 if (file
->size
<= VTOY_SIZE_1MB
&& grub_strcmp(node
->name
, "/boot/hdt.img") == 0)
1131 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
1134 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
1136 grub_file_read(file
, &data
, 1); // just read for hook trigger
1137 node
->offset
= grub_iso9660_get_last_read_pos(file
);
1144 node
->size
= file
->size
;
1145 g_valid_initrd_count
++;
1147 grub_file_close(file
);
1150 *filtcnt
= sizefilt
;
1152 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1156 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1160 initrd_info
*node
= NULL
;
1171 if (g_initrd_img_count
== 1)
1173 ventoy_set_env(args
[0], "0");
1174 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1177 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1179 if (node
->size
<= 0)
1184 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1190 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1191 ventoy_set_env(args
[0], buf
);
1195 debug("main initrd index:%d\n", index
);
1197 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1200 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1208 ventoy_linux_locate_initrd(1, &sizefilt
);
1210 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1212 ventoy_linux_locate_initrd(0, &sizefilt
);
1215 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1218 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1226 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1228 name
= (char *)(head
+ 1);
1229 while (name
[0] && count
< 2)
1231 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1233 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1236 else if (grub_strcmp(name
, filepath
) == 0)
1238 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1242 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1243 offset
= sizeof(cpio_newc_header
) + namelen
;
1244 offset
= ventoy_align(offset
, 4);
1245 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1246 offset
= ventoy_align(offset
, 4);
1248 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1249 name
= (char *)(head
+ 1);
1256 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1262 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1263 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1267 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1276 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1279 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1282 for (i
= 0; i
< 10; i
++)
1285 grub_file_seek(file
, (17 + i
) * 2048);
1286 grub_file_read(file
, buf
, 16);
1288 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1290 debug("Find SVD at VD %d\n", i
);
1291 g_svd_replace_offset
= (17 + i
) * 2048;
1298 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1301 grub_file_close(file
);
1303 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1306 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1312 if (args
[0][0] == '1')
1314 g_append_ext_sector
= 1;
1318 g_append_ext_sector
= 0;
1321 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1324 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1329 char *template_file
= NULL
;
1330 char *template_buf
= NULL
;
1331 char *persistent_buf
= NULL
;
1332 char *injection_buf
= NULL
;
1333 dud
*dudnode
= NULL
;
1335 const char *injection_file
= NULL
;
1336 grub_uint8_t
*buf
= NULL
;
1338 grub_uint32_t headlen
;
1339 grub_uint32_t initrd_head_len
;
1340 grub_uint32_t padlen
;
1341 grub_uint32_t img_chunk_size
;
1342 grub_uint32_t template_size
= 0;
1343 grub_uint32_t persistent_size
= 0;
1344 grub_uint32_t injection_size
= 0;
1345 grub_uint32_t dud_size
= 0;
1347 grub_file_t archfile
;
1348 grub_file_t tmpfile
;
1349 install_template
*template_node
= NULL
;
1350 ventoy_img_chunk_list chunk_list
;
1357 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1360 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1362 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1365 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1367 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1370 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1373 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1376 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1377 grub_file_close(file
);
1380 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1382 if (g_ventoy_cpio_buf
)
1384 grub_free(g_ventoy_cpio_buf
);
1385 g_ventoy_cpio_buf
= NULL
;
1386 g_ventoy_cpio_size
= 0;
1389 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1390 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1392 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1393 persistent_buf
= (char *)(chunk_list
.chunk
);
1396 template_file
= ventoy_plugin_get_cur_install_template(args
[1], &template_node
);
1399 debug("auto install template: <%s> <addr:%p> <len:%d>\n",
1400 template_file
, template_node
->filebuf
, template_node
->filelen
);
1402 template_size
= template_node
->filelen
;
1403 template_buf
= grub_malloc(template_size
);
1406 grub_memcpy(template_buf
, template_node
->filebuf
, template_size
);
1411 debug("auto install script skipped or not configed %s\n", args
[1]);
1414 injection_file
= ventoy_plugin_get_injection(args
[1]);
1417 debug("injection archive: <%s>\n", injection_file
);
1418 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1421 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1422 injection_size
= tmpfile
->size
;
1423 injection_buf
= grub_malloc(injection_size
);
1426 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1429 grub_file_close(tmpfile
);
1433 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1438 debug("injection not configed %s\n", args
[1]);
1441 dudnode
= ventoy_plugin_find_dud(args
[1]);
1444 debug("dud file: <%d>\n", dudnode
->dudnum
);
1445 ventoy_plugin_load_dud(dudnode
, args
[2]);
1446 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1448 if (dudnode
->files
[i
].size
> 0)
1450 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1456 debug("dud not configed %s\n", args
[1]);
1459 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1460 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1461 if (NULL
== g_ventoy_cpio_buf
)
1463 grub_file_close(file
);
1464 grub_file_close(archfile
);
1465 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1468 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1469 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1470 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1475 grub_file_read(archfile
, buf
, archfile
->size
);
1476 buf
+= (archfile
->size
- 4);
1477 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1482 /* get initrd head len */
1483 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1485 /* step1: insert image chunk data to cpio */
1486 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1487 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1491 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1492 buf
+= headlen
+ ventoy_align(template_size
, 4);
1493 grub_check_free(template_buf
);
1496 if (persistent_size
> 0 && persistent_buf
)
1498 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1499 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1500 grub_check_free(persistent_buf
);
1503 if (injection_size
> 0 && injection_buf
)
1505 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1506 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1508 grub_free(injection_buf
);
1509 injection_buf
= NULL
;
1514 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1516 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1517 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1518 dud_size
= dudnode
->files
[i
].size
;
1519 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1520 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1524 /* step2: insert os param to cpio */
1525 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1526 padlen
= sizeof(ventoy_os_param
);
1527 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1528 mod
= g_ventoy_cpio_size
% 2048;
1531 g_ventoy_cpio_size
+= 2048 - mod
;
1532 padlen
+= 2048 - mod
;
1535 /* update os param data size, the data will be updated before chain boot */
1536 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1537 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1539 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1540 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1541 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1543 grub_file_close(file
);
1544 grub_file_close(archfile
);
1546 if (grub_strcmp(args
[3], "busybox=64") == 0)
1548 debug("cpio busybox proc %s\n", args
[3]);
1549 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1551 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1553 debug("cpio busybox proc %s\n", args
[3]);
1554 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1556 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1558 debug("cpio busybox proc %s\n", args
[3]);
1559 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1562 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1565 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1572 grub_uint8_t
*bufend
;
1573 cpio_newc_header
*head
;
1576 const grub_uint8_t trailler
[124] = {
1577 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1578 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1579 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1580 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1581 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1582 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1583 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1584 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1590 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1596 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1597 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1599 grub_file_close(file
);
1601 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1602 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1604 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1605 mod
= bufsize
% 512;
1608 grub_memset(bufend
, 0, 512 - mod
);
1609 bufsize
+= 512 - mod
;
1612 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1614 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1615 name
= (char *)(head
+ 1);
1617 while (grub_strcmp(name
, "TRAILER!!!"))
1619 if (grub_strcmp(name
, "init") == 0)
1621 grub_memcpy(name
, "xxxx", 4);
1623 else if (grub_strcmp(name
, "linuxrc") == 0)
1625 grub_memcpy(name
, "vtoyxrc", 7);
1627 else if (grub_strcmp(name
, "sbin") == 0)
1629 grub_memcpy(name
, "vtoy", 4);
1631 else if (grub_strcmp(name
, "sbin/init") == 0)
1633 grub_memcpy(name
, "vtoy/vtoy", 9);
1636 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1637 offset
= sizeof(cpio_newc_header
) + namelen
;
1638 offset
= ventoy_align(offset
, 4);
1639 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1640 offset
= ventoy_align(offset
, 4);
1642 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1643 name
= (char *)(head
+ 1);
1647 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)g_ventoy_cpio_buf
);
1648 ventoy_set_env("ventoy_cpio_addr", value
);
1649 grub_snprintf(value
, sizeof(value
), "%d", bufsize
);
1650 ventoy_set_env("ventoy_cpio_size", value
);
1652 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1655 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1658 int ventoy_compatible
= 0;
1659 grub_uint32_t size
= 0;
1660 grub_uint64_t isosize
= 0;
1661 grub_uint32_t boot_catlog
= 0;
1662 grub_uint32_t img_chunk_size
= 0;
1663 grub_uint32_t override_count
= 0;
1664 grub_uint32_t override_size
= 0;
1665 grub_uint32_t virt_chunk_count
= 0;
1666 grub_uint32_t virt_chunk_size
= 0;
1669 const char *pLastChain
= NULL
;
1670 const char *compatible
;
1671 ventoy_chain_head
*chain
;
1677 compatible
= grub_env_get("ventoy_compatible");
1678 if (compatible
&& compatible
[0] == 'Y')
1680 ventoy_compatible
= 1;
1683 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1685 grub_printf("ventoy not ready\n");
1689 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1695 isosize
= file
->size
;
1697 len
= (int)grub_strlen(args
[0]);
1698 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1700 debug("boot catlog %u for img file\n", boot_catlog
);
1704 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1707 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1709 grub_env_set("LoadIsoEfiDriver", "on");
1714 if (ventoy_is_efi_os())
1716 grub_env_set("LoadIsoEfiDriver", "on");
1720 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1725 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1727 override_count
= ventoy_linux_get_override_chunk_count();
1728 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1730 if (ventoy_compatible
)
1732 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1736 override_size
= ventoy_linux_get_override_chunk_size();
1737 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1738 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1741 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1744 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1747 debug("free last chain memory %p\n", chain
);
1752 chain
= ventoy_alloc_chain(size
);
1755 grub_printf("Failed to alloc chain linux memory size %u\n", size
);
1756 grub_file_close(file
);
1760 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1761 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1762 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1763 grub_env_set("vtoy_chain_mem_size", envbuf
);
1765 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1767 /* part 1: os parameter */
1768 g_ventoy_chain_type
= ventoy_chain_linux
;
1769 ventoy_fill_os_param(file
, &(chain
->os_param
));
1771 /* part 2: chain head */
1772 disk
= file
->device
->disk
;
1773 chain
->disk_drive
= disk
->id
;
1774 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1775 chain
->real_img_size_in_bytes
= file
->size
;
1776 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1777 chain
->boot_catalog
= boot_catlog
;
1779 if (!ventoy_is_efi_os())
1781 grub_file_seek(file
, boot_catlog
* 2048);
1782 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1785 /* part 3: image chunk */
1786 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1787 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1788 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1790 if (ventoy_compatible
)
1795 /* part 4: override chunk */
1796 if (override_count
> 0)
1798 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1799 chain
->override_chunk_num
= override_count
;
1800 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1803 /* part 5: virt chunk */
1804 if (virt_chunk_count
> 0)
1806 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1807 chain
->virt_chunk_num
= virt_chunk_count
;
1808 ventoy_linux_fill_virt_data(isosize
, chain
);
1811 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1814 static char *ventoy_systemd_conf_tag(char *buf
, const char *tag
, int optional
)
1818 char *nextline
= NULL
;
1820 taglen
= grub_strlen(tag
);
1821 for (start
= buf
; start
; start
= nextline
)
1823 nextline
= ventoy_get_line(start
);
1824 while (ventoy_isspace(*start
))
1829 if (grub_strncmp(start
, tag
, taglen
) == 0 && (start
[taglen
] == ' ' || start
[taglen
] == '\t'))
1832 while (ventoy_isspace(*start
))
1842 debug("tag<%s> NOT found\n", tag
);
1847 static int ventoy_systemd_conf_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1852 char *filebuf
= NULL
;
1853 grub_file_t file
= NULL
;
1854 systemd_menu_ctx
*ctx
= (systemd_menu_ctx
*)data
;
1856 debug("ventoy_systemd_conf_hook %s\n", filename
);
1858 if (info
->dir
|| NULL
== grub_strstr(filename
, ".conf"))
1864 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/loader/entries/%s", ctx
->dev
, filename
);
1870 filebuf
= grub_zalloc(2 * file
->size
+ 8);
1876 bkbuf
= filebuf
+ file
->size
+ 4;
1877 grub_file_read(file
, bkbuf
, file
->size
);
1881 /* title --> menuentry */
1882 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1883 tag
= ventoy_systemd_conf_tag(filebuf
, "title", 0);
1884 vtoy_check_goto_out(tag
);
1885 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "menuentry \"%s\" {\n", tag
);
1888 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1889 tag
= ventoy_systemd_conf_tag(filebuf
, "linux", 0);
1895 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, " echo \"Downloading kernel ...\"\n linux %s ", tag
);
1897 /* kernel options */
1898 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1899 tag
= ventoy_systemd_conf_tag(filebuf
, "options", 0);
1900 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "%s \n", tag
? tag
: "");
1903 /* initrd xxx xxx xxx */
1904 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, " echo \"Downloading initrd ...\"\n initrd ");
1905 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1906 tag
= ventoy_systemd_conf_tag(filebuf
, "initrd", 1);
1909 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "%s ", tag
);
1910 tag
= ventoy_systemd_conf_tag(tag
+ grub_strlen(tag
) + 1, "initrd", 1);
1913 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "\n boot\n}\n");
1916 grub_check_free(filebuf
);
1917 grub_file_close(file
);
1921 grub_err_t
ventoy_cmd_linux_systemd_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1923 static char *buf
= NULL
;
1927 char *device_name
= NULL
;
1928 grub_device_t dev
= NULL
;
1929 systemd_menu_ctx ctx
;
1936 buf
= grub_malloc(VTOY_LINUX_SYSTEMD_MENU_MAX_BUF
);
1943 device_name
= grub_file_get_device_name(args
[0]);
1946 debug("failed to get device name %s\n", args
[0]);
1950 dev
= grub_device_open(device_name
);
1953 debug("failed to open device %s\n", device_name
);
1957 fs
= grub_fs_probe(dev
);
1960 debug("failed to probe fs %d\n", grub_errno
);
1967 ctx
.len
= VTOY_LINUX_SYSTEMD_MENU_MAX_BUF
;
1968 fs
->fs_dir(dev
, "/loader/entries", ventoy_systemd_conf_hook
, &ctx
);
1970 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
1971 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)buf
);
1972 grub_env_set(name
, value
);
1974 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
1975 grub_snprintf(value
, sizeof(value
), "%d", ctx
.pos
);
1976 grub_env_set(name
, value
);
1979 grub_check_free(device_name
);
1980 check_free(dev
, grub_device_close
);
1981 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);