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 VTOY_SKIP_SPACE(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 int ventoy_linux_initrd_collect_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
336 initrd_info
*img
= NULL
;
342 if (grub_strncmp(filename
, "initrd", 6) == 0)
344 len
= (int)grub_strlen(filename
);
345 if (grub_strcmp(filename
+ len
- 4, ".img") == 0)
347 img
= grub_zalloc(sizeof(initrd_info
));
350 grub_snprintf(img
->name
, sizeof(img
->name
), "/boot/%s", filename
);
352 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
358 if (g_initrd_img_list
)
360 img
->prev
= g_initrd_img_tail
;
361 g_initrd_img_tail
->next
= img
;
365 g_initrd_img_list
= img
;
368 g_initrd_img_tail
= img
;
369 g_initrd_img_count
++;
379 static int ventoy_linux_collect_boot_initrds(void)
382 grub_device_t dev
= NULL
;
384 dev
= grub_device_open("loop");
387 debug("failed to open device loop\n");
391 fs
= grub_fs_probe(dev
);
394 debug("failed to probe fs %d\n", grub_errno
);
398 fs
->fs_dir(dev
, "/boot", ventoy_linux_initrd_collect_hook
, NULL
);
404 static grub_err_t
ventoy_grub_cfg_initrd_collect(const char *fileName
)
410 int initrd_dollar
= 0;
411 grub_file_t file
= NULL
;
414 char *nextline
= NULL
;
415 initrd_info
*img
= NULL
;
417 debug("grub initrd collect %s\n", fileName
);
419 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", fileName
);
425 buf
= grub_zalloc(file
->size
+ 2);
428 grub_file_close(file
);
432 grub_file_read(file
, buf
, file
->size
);
434 for (start
= buf
; start
; start
= nextline
)
436 nextline
= ventoy_get_line(start
);
438 VTOY_SKIP_SPACE(start
);
440 if (grub_strncmp(start
, "initrd", 6) != 0)
446 while (*start
&& (!ventoy_isspace(*start
)))
451 VTOY_SKIP_SPACE(start
);
461 img
= grub_zalloc(sizeof(initrd_info
));
468 for (i
= 0; i
< 255 && (0 == ventoy_is_word_end(*start
)); i
++)
470 img
->name
[i
] = *start
++;
471 if (img
->name
[i
] == '$')
479 len
= (int)grub_strlen(img
->name
);
480 if (len
> 2 && img
->name
[len
- 1] == '"')
482 img
->name
[len
- 1] = 0;
484 debug("Remove quotation <%s>\n", img
->name
);
487 /* special process for /boot/initrd$XXX.img */
490 if (grub_strncmp(img
->name
, "/boot/initrd$", 13) == 0)
492 len
= (int)grub_strlen(img
->name
);
493 if (grub_strcmp(img
->name
+ len
- 4, ".img") == 0)
500 if (dollar
== 1 || ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
506 if (g_initrd_img_list
)
508 img
->prev
= g_initrd_img_tail
;
509 g_initrd_img_tail
->next
= img
;
513 g_initrd_img_list
= img
;
516 g_initrd_img_tail
= img
;
517 g_initrd_img_count
++;
520 if (*start
== ' ' || *start
== '\t')
522 VTOY_SKIP_SPACE(start
);
532 grub_file_close(file
);
534 if (initrd_dollar
> 0 && grub_strncmp(fileName
, "(loop)/", 7) == 0)
536 debug("collect initrd variable %d\n", initrd_dollar
);
537 ventoy_linux_collect_boot_initrds();
540 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
543 static int ventoy_grub_initrd_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
546 ventoy_initrd_ctx
*ctx
= (ventoy_initrd_ctx
*)data
;
550 debug("ventoy_grub_initrd_hook %s\n", filename
);
552 if (NULL
== grub_strstr(filename
, ".cfg") &&
553 NULL
== grub_strstr(filename
, ".CFG") &&
554 NULL
== grub_strstr(filename
, ".conf"))
559 debug("init hook dir <%s%s>\n", ctx
->path_prefix
, filename
);
561 grub_snprintf(filePath
, sizeof(filePath
) - 1, "%s%s", ctx
->dir_prefix
, filename
);
562 ventoy_grub_cfg_initrd_collect(filePath
);
567 grub_err_t
ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt
, int argc
, char **args
)
570 grub_device_t dev
= NULL
;
571 char *device_name
= NULL
;
572 ventoy_initrd_ctx ctx
;
582 debug("grub initrd collect %s %s\n", args
[0], args
[1]);
584 if (grub_strcmp(args
[0], "file") == 0)
586 return ventoy_grub_cfg_initrd_collect(args
[1]);
589 device_name
= grub_file_get_device_name(args
[1]);
592 debug("failed to get device name %s\n", args
[1]);
596 dev
= grub_device_open(device_name
);
599 debug("failed to open device %s\n", device_name
);
603 fs
= grub_fs_probe(dev
);
606 debug("failed to probe fs %d\n", grub_errno
);
610 ctx
.dir_prefix
= args
[1];
611 ctx
.path_prefix
= grub_strstr(args
[1], device_name
);
614 ctx
.path_prefix
+= grub_strlen(device_name
) + 1;
618 ctx
.path_prefix
= args
[1];
621 debug("ctx.path_prefix:<%s>\n", ctx
.path_prefix
);
623 fs
->fs_dir(dev
, ctx
.path_prefix
, ventoy_grub_initrd_hook
, &ctx
);
626 check_free(device_name
, grub_free
);
627 check_free(dev
, grub_device_close
);
630 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
633 grub_err_t
ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
635 initrd_info
*img
= NULL
;
640 debug("ventoy_cmd_specify_initrd_file %s\n", args
[0]);
642 img
= grub_zalloc(sizeof(initrd_info
));
648 grub_strncpy(img
->name
, args
[0], sizeof(img
->name
));
649 if (ventoy_find_initrd_by_name(g_initrd_img_list
, img
->name
))
651 debug("%s is already exist\n", args
[0]);
656 if (g_initrd_img_list
)
658 img
->prev
= g_initrd_img_tail
;
659 g_initrd_img_tail
->next
= img
;
663 g_initrd_img_list
= img
;
666 g_initrd_img_tail
= img
;
667 g_initrd_img_count
++;
670 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
673 static int ventoy_cpio_newc_get_int(char *value
)
677 grub_memcpy(buf
, value
, 8);
678 return (int)grub_strtoul(buf
, NULL
, 16);
681 static void ventoy_cpio_newc_fill_int(grub_uint32_t value
, char *buf
, int buflen
)
687 len
= grub_snprintf(intbuf
, sizeof(intbuf
), "%x", value
);
689 for (i
= 0; i
< buflen
; i
++)
696 grub_printf("int buf len overflow %d %d\n", len
, buflen
);
700 grub_memcpy(buf
+ buflen
- len
, intbuf
, len
);
704 int ventoy_cpio_newc_fill_head(void *buf
, int filesize
, const void *filedata
, const char *name
)
708 static grub_uint32_t cpio_ino
= 0xFFFFFFF0;
709 cpio_newc_header
*cpio
= (cpio_newc_header
*)buf
;
711 namelen
= grub_strlen(name
) + 1;
712 headlen
= sizeof(cpio_newc_header
) + namelen
;
713 headlen
= ventoy_align(headlen
, 4);
715 grub_memset(cpio
, '0', sizeof(cpio_newc_header
));
716 grub_memset(cpio
+ 1, 0, headlen
- sizeof(cpio_newc_header
));
718 grub_memcpy(cpio
->c_magic
, "070701", 6);
719 ventoy_cpio_newc_fill_int(cpio_ino
--, cpio
->c_ino
, 8);
720 ventoy_cpio_newc_fill_int(0100777, cpio
->c_mode
, 8);
721 ventoy_cpio_newc_fill_int(1, cpio
->c_nlink
, 8);
722 ventoy_cpio_newc_fill_int(filesize
, cpio
->c_filesize
, 8);
723 ventoy_cpio_newc_fill_int(namelen
, cpio
->c_namesize
, 8);
724 grub_memcpy(cpio
+ 1, name
, namelen
);
728 grub_memcpy((char *)cpio
+ headlen
, filedata
, filesize
);
734 static grub_uint32_t
ventoy_linux_get_virt_chunk_count(void)
737 grub_uint32_t count
= g_valid_initrd_count
;
739 if (g_conf_replace_count
> 0)
741 for (i
= 0; i
< g_conf_replace_count
; i
++)
743 if (g_conf_replace_offset
[i
] > 0)
750 if (g_append_ext_sector
> 0)
758 static grub_uint32_t
ventoy_linux_get_virt_chunk_size(void)
763 size
= (sizeof(ventoy_virt_chunk
) + g_ventoy_cpio_size
) * g_valid_initrd_count
;
765 if (g_conf_replace_count
> 0)
767 for (i
= 0; i
< g_conf_replace_count
; i
++)
769 if (g_conf_replace_offset
[i
] > 0)
771 size
+= sizeof(ventoy_virt_chunk
) + g_conf_replace_new_len_align
[i
];
776 if (g_append_ext_sector
> 0)
778 size
+= sizeof(ventoy_virt_chunk
) + VTOY_APPEND_EXT_SIZE
;
784 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
790 grub_uint64_t sector
;
791 grub_uint32_t offset
;
792 grub_uint32_t cpio_secs
;
793 grub_uint32_t initrd_secs
;
795 ventoy_virt_chunk
*cur
;
796 ventoy_grub_param_file_replace
*replace
= NULL
;
799 override
= (char *)chain
+ chain
->virt_chunk_offset
;
800 sector
= (isosize
+ 2047) / 2048;
801 cpio_secs
= g_ventoy_cpio_size
/ 2048;
803 offset
= ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk
);
804 cur
= (ventoy_virt_chunk
*)override
;
806 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
813 initrd_secs
= (grub_uint32_t
)((node
->size
+ 2047) / 2048);
815 cur
->mem_sector_start
= sector
;
816 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
817 cur
->mem_sector_offset
= offset
;
818 cur
->remap_sector_start
= cur
->mem_sector_end
;
819 cur
->remap_sector_end
= cur
->remap_sector_start
+ initrd_secs
;
820 cur
->org_sector_start
= (grub_uint32_t
)(node
->offset
/ 2048);
822 grub_memcpy(g_ventoy_runtime_buf
, &chain
->os_param
, sizeof(ventoy_os_param
));
824 grub_memset(name
, 0, 16);
825 grub_snprintf(name
, sizeof(name
), "initrd%03d", ++id
);
827 grub_memcpy(g_ventoy_initrd_head
+ 1, name
, 16);
828 ventoy_cpio_newc_fill_int((grub_uint32_t
)node
->size
, g_ventoy_initrd_head
->c_filesize
, 8);
830 grub_memcpy(override
+ offset
, g_ventoy_cpio_buf
, g_ventoy_cpio_size
);
832 chain
->virt_img_size_in_bytes
+= g_ventoy_cpio_size
+ initrd_secs
* 2048;
834 offset
+= g_ventoy_cpio_size
;
835 sector
+= cpio_secs
+ initrd_secs
;
840 /* Lenovo EasyStartup need an addional sector for boundary check */
841 if (g_append_ext_sector
> 0)
843 cpio_secs
= VTOY_APPEND_EXT_SIZE
/ 2048;
845 cur
->mem_sector_start
= sector
;
846 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
847 cur
->mem_sector_offset
= offset
;
848 cur
->remap_sector_start
= 0;
849 cur
->remap_sector_end
= 0;
850 cur
->org_sector_start
= 0;
852 grub_memset(override
+ offset
, 0, VTOY_APPEND_EXT_SIZE
);
854 chain
->virt_img_size_in_bytes
+= VTOY_APPEND_EXT_SIZE
;
856 offset
+= VTOY_APPEND_EXT_SIZE
;
862 if (g_conf_replace_count
> 0)
864 for (i
= 0; i
< g_conf_replace_count
; i
++)
866 if (g_conf_replace_offset
[i
] > 0)
868 cpio_secs
= g_conf_replace_new_len_align
[i
] / 2048;
870 cur
->mem_sector_start
= sector
;
871 cur
->mem_sector_end
= cur
->mem_sector_start
+ cpio_secs
;
872 cur
->mem_sector_offset
= offset
;
873 cur
->remap_sector_start
= 0;
874 cur
->remap_sector_end
= 0;
875 cur
->org_sector_start
= 0;
877 grub_memcpy(override
+ offset
, g_conf_replace_new_buf
[i
], g_conf_replace_new_len
[i
]);
879 chain
->virt_img_size_in_bytes
+= g_conf_replace_new_len_align
[i
];
881 replace
= g_grub_param
->img_replace
+ i
;
882 if (replace
->magic
== GRUB_IMG_REPLACE_MAGIC
)
884 replace
->new_file_virtual_id
= virtid
;
887 offset
+= g_conf_replace_new_len_align
[i
];
898 static grub_uint32_t
ventoy_linux_get_override_chunk_count(void)
901 grub_uint32_t count
= g_valid_initrd_count
;
903 if (g_conf_replace_count
> 0)
905 for (i
= 0; i
< g_conf_replace_count
; i
++)
907 if (g_conf_replace_offset
[i
] > 0)
914 if (g_svd_replace_offset
> 0)
922 static grub_uint32_t
ventoy_linux_get_override_chunk_size(void)
925 int count
= g_valid_initrd_count
;
927 if (g_conf_replace_count
> 0)
929 for (i
= 0; i
< g_conf_replace_count
; i
++)
931 if (g_conf_replace_offset
[i
] > 0)
938 if (g_svd_replace_offset
> 0)
943 return sizeof(ventoy_override_chunk
) * count
;
946 static void ventoy_linux_fill_override_data( grub_uint64_t isosize
, void *override
)
951 grub_uint32_t newlen
;
952 grub_uint64_t sector
;
953 ventoy_override_chunk
*cur
;
954 ventoy_iso9660_override
*dirent
;
955 ventoy_udf_override
*udf
;
957 sector
= (isosize
+ 2047) / 2048;
959 cur
= (ventoy_override_chunk
*)override
;
960 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
967 newlen
= (grub_uint32_t
)(node
->size
+ g_ventoy_cpio_size
);
971 newlen
+= 4 - mod
; /* cpio must align with 4 */
974 if (node
->iso_type
== 0)
976 dirent
= (ventoy_iso9660_override
*)node
->override_data
;
978 node
->override_length
= sizeof(ventoy_iso9660_override
);
979 dirent
->first_sector
= (grub_uint32_t
)sector
;
980 dirent
->size
= newlen
;
981 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
982 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
984 sector
+= (dirent
->size
+ 2047) / 2048;
988 udf
= (ventoy_udf_override
*)node
->override_data
;
990 node
->override_length
= sizeof(ventoy_udf_override
);
991 udf
->length
= newlen
;
992 udf
->position
= (grub_uint32_t
)sector
- node
->udf_start_block
;
994 sector
+= (udf
->length
+ 2047) / 2048;
997 cur
->img_offset
= node
->override_offset
;
998 cur
->override_size
= node
->override_length
;
999 grub_memcpy(cur
->override_data
, node
->override_data
, cur
->override_size
);
1003 if (g_conf_replace_count
> 0)
1005 for (i
= 0; i
< g_conf_replace_count
; i
++)
1007 if (g_conf_replace_offset
[i
] > 0)
1009 cur
->img_offset
= g_conf_replace_offset
[i
];
1010 cur
->override_size
= sizeof(ventoy_iso9660_override
);
1012 newlen
= (grub_uint32_t
)(g_conf_replace_new_len
[i
]);
1014 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
1015 dirent
->first_sector
= (grub_uint32_t
)sector
;
1016 dirent
->size
= newlen
;
1017 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1018 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1020 sector
+= (dirent
->size
+ 2047) / 2048;
1026 if (g_svd_replace_offset
> 0)
1028 cur
->img_offset
= g_svd_replace_offset
;
1029 cur
->override_size
= 1;
1030 cur
->override_data
[0] = 0xFF;
1037 grub_err_t
ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1047 grub_snprintf(buf
, sizeof(buf
), "%d", g_initrd_img_count
);
1048 grub_env_set(args
[0], buf
);
1051 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1054 grub_err_t
ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1064 grub_snprintf(buf
, sizeof(buf
), "%d", g_valid_initrd_count
);
1065 grub_env_set(args
[0], buf
);
1068 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1071 static grub_err_t
ventoy_linux_locate_initrd(int filt
, int *filtcnt
)
1079 debug("ventoy_linux_locate_initrd %d\n", filt
);
1081 g_valid_initrd_count
= 0;
1083 if (grub_env_get("INITRD_NO_SIZE_FILT"))
1088 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1090 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->name
);
1096 debug("file <%s> size:%d\n", node
->name
, (int)file
->size
);
1098 /* initrd file too small */
1100 && (NULL
== grub_strstr(node
->name
, "minirt.gz"))
1101 && (NULL
== grub_strstr(node
->name
, "initrd.xz"))
1104 if (filt
> 0 && file
->size
<= g_ventoy_cpio_size
+ 2048)
1106 debug("file size too small %d\n", (int)g_ventoy_cpio_size
);
1107 grub_file_close(file
);
1114 if (file
->size
<= VTOY_SIZE_1MB
&& grub_strcmp(node
->name
, "/boot/hdt.img") == 0)
1119 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
1122 node
->override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
1124 grub_file_read(file
, &data
, 1); // just read for hook trigger
1125 node
->offset
= grub_iso9660_get_last_read_pos(file
);
1132 node
->size
= file
->size
;
1133 g_valid_initrd_count
++;
1135 grub_file_close(file
);
1138 *filtcnt
= sizefilt
;
1140 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1144 grub_err_t
ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1148 initrd_info
*node
= NULL
;
1159 if (g_initrd_img_count
== 1)
1161 ventoy_set_env(args
[0], "0");
1162 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1165 for (node
= g_initrd_img_list
; node
; node
= node
->next
)
1167 if (node
->size
<= 0)
1172 if (grub_strstr(node
->name
, "ucode") || grub_strstr(node
->name
, "-firmware"))
1178 grub_snprintf(buf
, sizeof(buf
), "%d", index
);
1179 ventoy_set_env(args
[0], buf
);
1183 debug("main initrd index:%d\n", index
);
1185 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1188 grub_err_t
ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1196 ventoy_linux_locate_initrd(1, &sizefilt
);
1198 if (g_valid_initrd_count
== 0 && sizefilt
> 0)
1200 ventoy_linux_locate_initrd(0, &sizefilt
);
1203 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1206 static int ventoy_cpio_busybox64(cpio_newc_header
*head
, const char *file
)
1214 grub_snprintf(filepath
, sizeof(filepath
), "ventoy/busybox/%s", file
);
1216 name
= (char *)(head
+ 1);
1217 while (name
[0] && count
< 2)
1219 if (grub_strcmp(name
, "ventoy/busybox/ash") == 0)
1221 grub_memcpy(name
, "ventoy/busybox/32h", 18);
1224 else if (grub_strcmp(name
, filepath
) == 0)
1226 grub_memcpy(name
, "ventoy/busybox/ash", 18);
1230 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1231 offset
= sizeof(cpio_newc_header
) + namelen
;
1232 offset
= ventoy_align(offset
, 4);
1233 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1234 offset
= ventoy_align(offset
, 4);
1236 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1237 name
= (char *)(head
+ 1);
1244 grub_err_t
ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1250 debug("ventoy_cmd_busybox_64 %d\n", argc
);
1251 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, args
[0]);
1255 grub_err_t
ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1264 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1267 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1270 for (i
= 0; i
< 10; i
++)
1273 grub_file_seek(file
, (17 + i
) * 2048);
1274 grub_file_read(file
, buf
, 16);
1276 if (buf
[0] == 2 && grub_strncmp(buf
+ 1, "CD001", 5) == 0)
1278 debug("Find SVD at VD %d\n", i
);
1279 g_svd_replace_offset
= (17 + i
) * 2048;
1286 debug("SVD not found %d\n", (int)g_svd_replace_offset
);
1289 grub_file_close(file
);
1291 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1294 grub_err_t
ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1300 if (args
[0][0] == '1')
1302 g_append_ext_sector
= 1;
1306 g_append_ext_sector
= 0;
1309 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1312 grub_err_t
ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1317 char *template_file
= NULL
;
1318 char *template_buf
= NULL
;
1319 char *persistent_buf
= NULL
;
1320 char *injection_buf
= NULL
;
1321 dud
*dudnode
= NULL
;
1323 const char *injection_file
= NULL
;
1324 grub_uint8_t
*buf
= NULL
;
1326 grub_uint32_t headlen
;
1327 grub_uint32_t initrd_head_len
;
1328 grub_uint32_t padlen
;
1329 grub_uint32_t img_chunk_size
;
1330 grub_uint32_t template_size
= 0;
1331 grub_uint32_t persistent_size
= 0;
1332 grub_uint32_t injection_size
= 0;
1333 grub_uint32_t dud_size
= 0;
1335 grub_file_t archfile
;
1336 grub_file_t tmpfile
;
1337 install_template
*template_node
= NULL
;
1338 ventoy_img_chunk_list chunk_list
;
1345 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s cpiofile\n", cmd_raw_name
);
1348 if (g_img_chunk_list
.chunk
== NULL
|| g_img_chunk_list
.cur_chunk
== 0)
1350 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "image chunk is null\n");
1353 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1355 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_COMM_CPIO
);
1358 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_COMM_CPIO
);
1361 archfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/%s", args
[0], VTOY_ARCH_CPIO
);
1364 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s/%s\n", args
[0], VTOY_ARCH_CPIO
);
1365 grub_file_close(file
);
1368 debug("load %s %s success\n", VTOY_COMM_CPIO
, VTOY_ARCH_CPIO
);
1370 if (g_ventoy_cpio_buf
)
1372 grub_free(g_ventoy_cpio_buf
);
1373 g_ventoy_cpio_buf
= NULL
;
1374 g_ventoy_cpio_size
= 0;
1377 rc
= ventoy_plugin_get_persistent_chunklist(args
[1], -1, &chunk_list
);
1378 if (rc
== 0 && chunk_list
.cur_chunk
> 0 && chunk_list
.chunk
)
1380 persistent_size
= chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1381 persistent_buf
= (char *)(chunk_list
.chunk
);
1384 template_file
= ventoy_plugin_get_cur_install_template(args
[1], &template_node
);
1387 debug("auto install template: <%s> <addr:%p> <len:%d>\n",
1388 template_file
, template_node
->filebuf
, template_node
->filelen
);
1390 template_size
= template_node
->filelen
;
1391 template_buf
= grub_malloc(template_size
);
1394 grub_memcpy(template_buf
, template_node
->filebuf
, template_size
);
1399 debug("auto install script skipped or not configed %s\n", args
[1]);
1402 injection_file
= ventoy_plugin_get_injection(args
[1]);
1405 debug("injection archive: <%s>\n", injection_file
);
1406 tmpfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[2], injection_file
);
1409 debug("injection archive size:%d\n", (int)tmpfile
->size
);
1410 injection_size
= tmpfile
->size
;
1411 injection_buf
= grub_malloc(injection_size
);
1414 grub_file_read(tmpfile
, injection_buf
, injection_size
);
1417 grub_file_close(tmpfile
);
1421 debug("Failed to open injection archive %s%s\n", args
[2], injection_file
);
1426 debug("injection not configed %s\n", args
[1]);
1429 dudnode
= ventoy_plugin_find_dud(args
[1]);
1432 debug("dud file: <%d>\n", dudnode
->dudnum
);
1433 ventoy_plugin_load_dud(dudnode
, args
[2]);
1434 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1436 if (dudnode
->files
[i
].size
> 0)
1438 dud_size
+= dudnode
->files
[i
].size
+ sizeof(cpio_newc_header
);
1444 debug("dud not configed %s\n", args
[1]);
1447 g_ventoy_cpio_buf
= grub_malloc(file
->size
+ archfile
->size
+ 40960 + template_size
+
1448 persistent_size
+ injection_size
+ dud_size
+ img_chunk_size
);
1449 if (NULL
== g_ventoy_cpio_buf
)
1451 grub_file_close(file
);
1452 grub_file_close(archfile
);
1453 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't alloc memory %llu\n", file
->size
);
1456 grub_file_read(file
, g_ventoy_cpio_buf
, file
->size
);
1457 buf
= (grub_uint8_t
*)(g_ventoy_cpio_buf
+ file
->size
- 4);
1458 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1463 grub_file_read(archfile
, buf
, archfile
->size
);
1464 buf
+= (archfile
->size
- 4);
1465 while (*((grub_uint32_t
*)buf
) != 0x37303730)
1470 /* get initrd head len */
1471 initrd_head_len
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "initrd000.xx");
1473 /* step1: insert image chunk data to cpio */
1474 headlen
= ventoy_cpio_newc_fill_head(buf
, img_chunk_size
, g_img_chunk_list
.chunk
, "ventoy/ventoy_image_map");
1475 buf
+= headlen
+ ventoy_align(img_chunk_size
, 4);
1479 headlen
= ventoy_cpio_newc_fill_head(buf
, template_size
, template_buf
, "ventoy/autoinstall");
1480 buf
+= headlen
+ ventoy_align(template_size
, 4);
1481 grub_check_free(template_buf
);
1484 if (persistent_size
> 0 && persistent_buf
)
1486 headlen
= ventoy_cpio_newc_fill_head(buf
, persistent_size
, persistent_buf
, "ventoy/ventoy_persistent_map");
1487 buf
+= headlen
+ ventoy_align(persistent_size
, 4);
1488 grub_check_free(persistent_buf
);
1491 if (injection_size
> 0 && injection_buf
)
1493 headlen
= ventoy_cpio_newc_fill_head(buf
, injection_size
, injection_buf
, "ventoy/ventoy_injection");
1494 buf
+= headlen
+ ventoy_align(injection_size
, 4);
1496 grub_free(injection_buf
);
1497 injection_buf
= NULL
;
1502 for (i
= 0; i
< dudnode
->dudnum
; i
++)
1504 pos
= grub_strrchr(dudnode
->dudpath
[i
].path
, '.');
1505 grub_snprintf(tmpname
, sizeof(tmpname
), "ventoy/ventoy_dud%d%s", i
, (pos
? pos
: ".iso"));
1506 dud_size
= dudnode
->files
[i
].size
;
1507 headlen
= ventoy_cpio_newc_fill_head(buf
, dud_size
, dudnode
->files
[i
].buf
, tmpname
);
1508 buf
+= headlen
+ ventoy_align(dud_size
, 4);
1512 /* step2: insert os param to cpio */
1513 headlen
= ventoy_cpio_newc_fill_head(buf
, 0, NULL
, "ventoy/ventoy_os_param");
1514 padlen
= sizeof(ventoy_os_param
);
1515 g_ventoy_cpio_size
= (grub_uint32_t
)(buf
- g_ventoy_cpio_buf
) + headlen
+ padlen
+ initrd_head_len
;
1516 mod
= g_ventoy_cpio_size
% 2048;
1519 g_ventoy_cpio_size
+= 2048 - mod
;
1520 padlen
+= 2048 - mod
;
1523 /* update os param data size, the data will be updated before chain boot */
1524 ventoy_cpio_newc_fill_int(padlen
, ((cpio_newc_header
*)buf
)->c_filesize
, 8);
1525 g_ventoy_runtime_buf
= (grub_uint8_t
*)buf
+ headlen
;
1527 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1528 g_ventoy_initrd_head
= (cpio_newc_header
*)(g_ventoy_runtime_buf
+ padlen
);
1529 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head
, 0, NULL
, "initrd000.xx");
1531 grub_file_close(file
);
1532 grub_file_close(archfile
);
1534 if (grub_strcmp(args
[3], "busybox=64") == 0)
1536 debug("cpio busybox proc %s\n", args
[3]);
1537 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "64h");
1539 else if (grub_strcmp(args
[3], "busybox=a64") == 0)
1541 debug("cpio busybox proc %s\n", args
[3]);
1542 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "a64");
1544 else if (grub_strcmp(args
[3], "busybox=m64") == 0)
1546 debug("cpio busybox proc %s\n", args
[3]);
1547 ventoy_cpio_busybox64((cpio_newc_header
*)g_ventoy_cpio_buf
, "m64");
1550 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1553 grub_err_t
ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1560 grub_uint8_t
*bufend
;
1561 cpio_newc_header
*head
;
1563 const grub_uint8_t trailler
[124] = {
1564 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1565 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1566 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1567 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1568 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1569 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1570 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1571 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1577 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], args
[1]);
1583 grub_memset(g_ventoy_runtime_buf
, 0, sizeof(ventoy_os_param
));
1584 ventoy_fill_os_param(file
, (ventoy_os_param
*)g_ventoy_runtime_buf
);
1586 grub_file_close(file
);
1588 grub_memcpy(g_ventoy_initrd_head
, trailler
, sizeof(trailler
));
1589 bufend
= (grub_uint8_t
*)g_ventoy_initrd_head
+ sizeof(trailler
);
1591 bufsize
= (int)(bufend
- g_ventoy_cpio_buf
);
1592 mod
= bufsize
% 512;
1595 grub_memset(bufend
, 0, 512 - mod
);
1596 bufsize
+= 512 - mod
;
1599 if (argc
> 1 && grub_strcmp(args
[2], "noinit") == 0)
1601 head
= (cpio_newc_header
*)g_ventoy_cpio_buf
;
1602 name
= (char *)(head
+ 1);
1604 while (grub_strcmp(name
, "TRAILER!!!"))
1606 if (grub_strcmp(name
, "init") == 0)
1608 grub_memcpy(name
, "xxxx", 4);
1610 else if (grub_strcmp(name
, "linuxrc") == 0)
1612 grub_memcpy(name
, "vtoyxrc", 7);
1614 else if (grub_strcmp(name
, "sbin") == 0)
1616 grub_memcpy(name
, "vtoy", 4);
1618 else if (grub_strcmp(name
, "sbin/init") == 0)
1620 grub_memcpy(name
, "vtoy/vtoy", 9);
1623 namelen
= ventoy_cpio_newc_get_int(head
->c_namesize
);
1624 offset
= sizeof(cpio_newc_header
) + namelen
;
1625 offset
= ventoy_align(offset
, 4);
1626 offset
+= ventoy_cpio_newc_get_int(head
->c_filesize
);
1627 offset
= ventoy_align(offset
, 4);
1629 head
= (cpio_newc_header
*)((char *)head
+ offset
);
1630 name
= (char *)(head
+ 1);
1634 ventoy_memfile_env_set("ventoy_cpio", g_ventoy_cpio_buf
, (ulonglong
)bufsize
);
1636 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1639 grub_err_t
ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1642 int ventoy_compatible
= 0;
1643 grub_uint32_t size
= 0;
1644 grub_uint64_t isosize
= 0;
1645 grub_uint32_t boot_catlog
= 0;
1646 grub_uint32_t img_chunk_size
= 0;
1647 grub_uint32_t override_count
= 0;
1648 grub_uint32_t override_size
= 0;
1649 grub_uint32_t virt_chunk_count
= 0;
1650 grub_uint32_t virt_chunk_size
= 0;
1653 const char *pLastChain
= NULL
;
1654 const char *compatible
;
1655 ventoy_chain_head
*chain
;
1660 compatible
= grub_env_get("ventoy_compatible");
1661 if (compatible
&& compatible
[0] == 'Y')
1663 ventoy_compatible
= 1;
1666 if ((NULL
== g_img_chunk_list
.chunk
) || (0 == ventoy_compatible
&& g_ventoy_cpio_buf
== NULL
))
1668 grub_printf("ventoy not ready\n");
1672 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1678 isosize
= file
->size
;
1680 len
= (int)grub_strlen(args
[0]);
1681 if (len
>= 4 && 0 == grub_strcasecmp(args
[0] + len
- 4, ".img"))
1683 debug("boot catlog %u for img file\n", boot_catlog
);
1687 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1690 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1692 grub_env_set("LoadIsoEfiDriver", "on");
1697 if (ventoy_is_efi_os())
1699 grub_env_set("LoadIsoEfiDriver", "on");
1703 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1708 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1710 override_count
= ventoy_linux_get_override_chunk_count();
1711 virt_chunk_count
= ventoy_linux_get_virt_chunk_count();
1713 if (ventoy_compatible
)
1715 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1719 override_size
= ventoy_linux_get_override_chunk_size();
1720 virt_chunk_size
= ventoy_linux_get_virt_chunk_size();
1721 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1724 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1727 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1730 debug("free last chain memory %p\n", chain
);
1735 chain
= ventoy_alloc_chain(size
);
1738 grub_printf("Failed to alloc chain linux memory size %u\n", size
);
1739 grub_file_close(file
);
1743 ventoy_memfile_env_set("vtoy_chain_mem", chain
, (ulonglong
)size
);
1745 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1747 /* part 1: os parameter */
1748 g_ventoy_chain_type
= ventoy_chain_linux
;
1749 ventoy_fill_os_param(file
, &(chain
->os_param
));
1751 /* part 2: chain head */
1752 disk
= file
->device
->disk
;
1753 chain
->disk_drive
= disk
->id
;
1754 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1755 chain
->real_img_size_in_bytes
= file
->size
;
1756 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1757 chain
->boot_catalog
= boot_catlog
;
1759 if (!ventoy_is_efi_os())
1761 grub_file_seek(file
, boot_catlog
* 2048);
1762 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1765 /* part 3: image chunk */
1766 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1767 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1768 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1770 if (ventoy_compatible
)
1775 /* part 4: override chunk */
1776 if (override_count
> 0)
1778 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1779 chain
->override_chunk_num
= override_count
;
1780 ventoy_linux_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1783 /* part 5: virt chunk */
1784 if (virt_chunk_count
> 0)
1786 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1787 chain
->virt_chunk_num
= virt_chunk_count
;
1788 ventoy_linux_fill_virt_data(isosize
, chain
);
1791 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1794 static char *ventoy_systemd_conf_tag(char *buf
, const char *tag
, int optional
)
1798 char *nextline
= NULL
;
1800 taglen
= grub_strlen(tag
);
1801 for (start
= buf
; start
; start
= nextline
)
1803 nextline
= ventoy_get_line(start
);
1804 VTOY_SKIP_SPACE(start
);
1806 if (grub_strncmp(start
, tag
, taglen
) == 0 && (start
[taglen
] == ' ' || start
[taglen
] == '\t'))
1809 VTOY_SKIP_SPACE(start
);
1816 debug("tag<%s> NOT found\n", tag
);
1821 static int ventoy_systemd_conf_hook(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1826 char *filebuf
= NULL
;
1827 grub_file_t file
= NULL
;
1828 systemd_menu_ctx
*ctx
= (systemd_menu_ctx
*)data
;
1830 debug("ventoy_systemd_conf_hook %s\n", filename
);
1832 if (info
->dir
|| NULL
== grub_strstr(filename
, ".conf"))
1838 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/loader/entries/%s", ctx
->dev
, filename
);
1844 filebuf
= grub_zalloc(2 * file
->size
+ 8);
1850 bkbuf
= filebuf
+ file
->size
+ 4;
1851 grub_file_read(file
, bkbuf
, file
->size
);
1855 /* title --> menuentry */
1856 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1857 tag
= ventoy_systemd_conf_tag(filebuf
, "title", 0);
1858 vtoy_check_goto_out(tag
);
1859 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "menuentry \"%s\" {\n", tag
);
1862 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1863 tag
= ventoy_systemd_conf_tag(filebuf
, "linux", 0);
1869 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, " echo \"Downloading kernel ...\"\n linux %s ", tag
);
1871 /* kernel options */
1872 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1873 tag
= ventoy_systemd_conf_tag(filebuf
, "options", 0);
1874 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "%s \n", tag
? tag
: "");
1877 /* initrd xxx xxx xxx */
1878 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, " echo \"Downloading initrd ...\"\n initrd ");
1879 grub_memcpy(filebuf
, bkbuf
, file
->size
);
1880 tag
= ventoy_systemd_conf_tag(filebuf
, "initrd", 1);
1883 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "%s ", tag
);
1884 tag
= ventoy_systemd_conf_tag(tag
+ grub_strlen(tag
) + 1, "initrd", 1);
1887 vtoy_len_ssprintf(ctx
->buf
, ctx
->pos
, ctx
->len
, "\n boot\n}\n");
1890 grub_check_free(filebuf
);
1891 grub_file_close(file
);
1895 grub_err_t
ventoy_cmd_linux_systemd_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1897 static char *buf
= NULL
;
1899 char *device_name
= NULL
;
1900 grub_device_t dev
= NULL
;
1901 systemd_menu_ctx ctx
;
1908 buf
= grub_malloc(VTOY_LINUX_SYSTEMD_MENU_MAX_BUF
);
1915 device_name
= grub_file_get_device_name(args
[0]);
1918 debug("failed to get device name %s\n", args
[0]);
1922 dev
= grub_device_open(device_name
);
1925 debug("failed to open device %s\n", device_name
);
1929 fs
= grub_fs_probe(dev
);
1932 debug("failed to probe fs %d\n", grub_errno
);
1939 ctx
.len
= VTOY_LINUX_SYSTEMD_MENU_MAX_BUF
;
1940 fs
->fs_dir(dev
, "/loader/entries", ventoy_systemd_conf_hook
, &ctx
);
1942 ventoy_memfile_env_set(args
[1], buf
, (ulonglong
)(ctx
.pos
));
1945 grub_check_free(device_name
);
1946 check_free(dev
, grub_device_close
);
1947 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1950 static int ventoy_limine_path_convert(char *path
)
1952 char newpath
[256] = {0};
1954 if (grub_strncmp(path
, "boot://2/", 9) == 0)
1956 grub_snprintf(newpath
, sizeof(newpath
), "(vtimghd,2)/%s", path
+ 9);
1958 else if (grub_strncmp(path
, "boot://1/", 9) == 0)
1960 grub_snprintf(newpath
, sizeof(newpath
), "(vtimghd,1)/%s", path
+ 9);
1965 grub_snprintf(path
, 1024, "%s", newpath
);
1971 grub_err_t
ventoy_cmd_linux_limine_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1975 int len
= VTOY_LINUX_SYSTEMD_MENU_MAX_BUF
;
1976 char *filebuf
= NULL
;
1978 char *nextline
= NULL
;
1979 grub_file_t file
= NULL
;
1981 char *kernel
= NULL
;
1982 char *initrd
= NULL
;
1984 static char *buf
= NULL
;
1991 buf
= grub_malloc(len
+ 4 * 1024);
1999 kernel
= title
+ 1024;
2000 initrd
= kernel
+ 1024;
2001 param
= initrd
+ 1024;
2003 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, args
[0]);
2009 filebuf
= grub_zalloc(file
->size
+ 8);
2015 grub_file_read(file
, filebuf
, file
->size
);
2016 grub_file_close(file
);
2019 title
[0] = kernel
[0] = initrd
[0] = param
[0] = 0;
2020 for (start
= filebuf
; start
; start
= nextline
)
2022 nextline
= ventoy_get_line(start
);
2023 VTOY_SKIP_SPACE(start
);
2025 if (start
[0] == ':')
2027 if (start
[1] == ':')
2029 grub_snprintf(title
, 1024, "%s", start
+ 2);
2035 vtoy_len_ssprintf(buf
, pos
, len
, "}\n");
2039 if (nextline
&& nextline
[0] == ':' && nextline
[1] == ':')
2041 vtoy_len_ssprintf(buf
, pos
, len
, "submenu \"[+] %s\" {\n", start
+ 2);
2047 grub_snprintf(title
, 1024, "%s", start
+ 1);
2051 else if (grub_strncmp(start
, "KERNEL_PATH=", 12) == 0)
2053 grub_snprintf(kernel
, 1024, "%s", start
+ 12);
2055 else if (grub_strncmp(start
, "MODULE_PATH=", 12) == 0)
2057 grub_snprintf(initrd
, 1024, "%s", start
+ 12);
2059 else if (grub_strncmp(start
, "KERNEL_CMDLINE=", 15) == 0)
2061 grub_snprintf(param
, 1024, "%s", start
+ 15);
2064 if (title
[0] && kernel
[0] && initrd
[0] && param
[0])
2066 ventoy_limine_path_convert(kernel
);
2067 ventoy_limine_path_convert(initrd
);
2069 vtoy_len_ssprintf(buf
, pos
, len
, "menuentry \"%s\" {\n", title
);
2070 vtoy_len_ssprintf(buf
, pos
, len
, " echo \"Downloading kernel ...\"\n linux %s %s\n", kernel
, param
);
2071 vtoy_len_ssprintf(buf
, pos
, len
, " echo \"Downloading initrd ...\"\n initrd %s\n", initrd
);
2072 vtoy_len_ssprintf(buf
, pos
, len
, "}\n");
2074 title
[0] = kernel
[0] = initrd
[0] = param
[0] = 0;
2080 vtoy_len_ssprintf(buf
, pos
, len
, "}\n");
2084 ventoy_memfile_env_set(args
[1], buf
, (ulonglong
)pos
);
2087 grub_check_free(filebuf
);
2088 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);