]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
8c7a8ff9b5a82bf05677f697a056f3fa391a0b94
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_linux.c
1 /******************************************************************************
2 * ventoy_linux.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20 #include <grub/types.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/err.h>
24 #include <grub/dl.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>
34 #include <grub/net.h>
35 #include <grub/time.h>
36 #include <grub/ventoy.h>
37 #include "ventoy_def.h"
38
39 GRUB_MOD_LICENSE ("GPLv3+");
40
41 char * ventoy_get_line(char *start)
42 {
43 if (start == NULL)
44 {
45 return NULL;
46 }
47
48 while (*start && *start != '\n')
49 {
50 start++;
51 }
52
53 if (*start == 0)
54 {
55 return NULL;
56 }
57 else
58 {
59 *start = 0;
60 return start + 1;
61 }
62 }
63
64 static initrd_info * ventoy_find_initrd_by_name(initrd_info *list, const char *name)
65 {
66 initrd_info *node = list;
67
68 while (node)
69 {
70 if (grub_strcmp(node->name, name) == 0)
71 {
72 return node;
73 }
74 node = node->next;
75 }
76
77 return NULL;
78 }
79
80 grub_err_t ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args)
81 {
82 initrd_info *node = g_initrd_img_list;
83 initrd_info *next;
84
85 (void)ctxt;
86 (void)argc;
87 (void)args;
88
89 while (node)
90 {
91 next = node->next;
92 grub_free(node);
93 node = next;
94 }
95
96 g_initrd_img_list = NULL;
97 g_initrd_img_tail = NULL;
98 g_initrd_img_count = 0;
99 g_valid_initrd_count = 0;
100
101 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
102 }
103
104 grub_err_t ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args)
105 {
106 int i = 0;
107 initrd_info *node = g_initrd_img_list;
108
109 (void)ctxt;
110 (void)argc;
111 (void)args;
112
113 grub_printf("###################\n");
114 grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count);
115
116 while (node)
117 {
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);
121 node = node->next;
122 }
123
124 grub_printf("###################\n");
125
126 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
127 }
128
129 static void ventoy_parse_directory(char *path, char *dir, int buflen)
130 {
131 int end;
132 char *pos;
133
134 pos = grub_strstr(path, ")");
135 if (!pos)
136 {
137 pos = path;
138 }
139
140 end = grub_snprintf(dir, buflen, "%s", pos + 1);
141 while (end > 0)
142 {
143 if (dir[end] == '/')
144 {
145 dir[end + 1] = 0;
146 break;
147 }
148 end--;
149 }
150 }
151
152 static grub_err_t ventoy_isolinux_initrd_collect(grub_file_t file, const char *prefix)
153 {
154 int i = 0;
155 int offset;
156 int prefixlen = 0;
157 char *buf = NULL;
158 char *pos = NULL;
159 char *start = NULL;
160 char *nextline = NULL;
161 initrd_info *img = NULL;
162
163 prefixlen = grub_strlen(prefix);
164
165 buf = grub_zalloc(file->size + 2);
166 if (!buf)
167 {
168 return 0;
169 }
170
171 grub_file_read(file, buf, file->size);
172
173 for (start = buf; start; start = nextline)
174 {
175 nextline = ventoy_get_line(start);
176
177 while (ventoy_isspace(*start))
178 {
179 start++;
180 }
181
182 offset = 7; // strlen("initrd=") or "INITRD " or "initrd "
183 pos = grub_strstr(start, "initrd=");
184 if (pos == NULL)
185 {
186 pos = start;
187
188 if (grub_strncmp(start, "INITRD", 6) != 0 && grub_strncmp(start, "initrd", 6) != 0)
189 {
190 if (grub_strstr(start, "xen") &&
191 ((pos = grub_strstr(start, "--- /install.img")) != NULL ||
192 (pos = grub_strstr(start, "--- initrd.img")) != NULL
193 ))
194 {
195 offset = 4; // "--- "
196 }
197 else
198 {
199 continue;
200 }
201 }
202 }
203
204 pos += offset;
205
206 while (1)
207 {
208 i = 0;
209 img = grub_zalloc(sizeof(initrd_info));
210 if (!img)
211 {
212 break;
213 }
214
215 if (*pos != '/')
216 {
217 grub_strcpy(img->name, prefix);
218 i = prefixlen;
219 }
220
221 while (i < 255 && (0 == ventoy_is_word_end(*pos)))
222 {
223 img->name[i++] = *pos++;
224 }
225
226 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
227 {
228 grub_free(img);
229 }
230 else
231 {
232 if (g_initrd_img_list)
233 {
234 img->prev = g_initrd_img_tail;
235 g_initrd_img_tail->next = img;
236 }
237 else
238 {
239 g_initrd_img_list = img;
240 }
241
242 g_initrd_img_tail = img;
243 g_initrd_img_count++;
244 }
245
246 if (*pos == ',')
247 {
248 pos++;
249 }
250 else
251 {
252 break;
253 }
254 }
255 }
256
257 grub_free(buf);
258 return GRUB_ERR_NONE;
259 }
260
261 static int ventoy_isolinux_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
262 {
263 grub_file_t file = NULL;
264 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
265
266 (void)info;
267
268 if (NULL == grub_strstr(filename, ".cfg") && NULL == grub_strstr(filename, ".CFG"))
269 {
270 return 0;
271 }
272
273 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
274
275 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ctx->path_prefix, filename);
276 if (!file)
277 {
278 return 0;
279 }
280
281 ventoy_isolinux_initrd_collect(file, ctx->dir_prefix);
282 grub_file_close(file);
283
284 return 0;
285 }
286
287 grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
288 {
289 grub_fs_t fs;
290 grub_device_t dev = NULL;
291 char *device_name = NULL;
292 ventoy_initrd_ctx ctx;
293 char directory[256];
294
295 (void)ctxt;
296 (void)argc;
297
298 device_name = grub_file_get_device_name(args[0]);
299 if (!device_name)
300 {
301 goto end;
302 }
303
304 dev = grub_device_open(device_name);
305 if (!dev)
306 {
307 goto end;
308 }
309
310 fs = grub_fs_probe(dev);
311 if (!fs)
312 {
313 goto end;
314 }
315
316 debug("isolinux initrd collect %s\n", args[0]);
317
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;
321
322 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx.path_prefix, ctx.dir_prefix);
323
324 fs->fs_dir(dev, directory, ventoy_isolinux_initrd_hook, &ctx);
325
326 end:
327 check_free(device_name, grub_free);
328 check_free(dev, grub_device_close);
329
330 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
331 }
332
333 static grub_err_t ventoy_grub_cfg_initrd_collect(const char *fileName)
334 {
335 int i = 0;
336 int dollar = 0;
337 grub_file_t file = NULL;
338 char *buf = NULL;
339 char *start = NULL;
340 char *nextline = NULL;
341 initrd_info *img = NULL;
342
343 debug("grub initrd collect %s\n", fileName);
344
345 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", fileName);
346 if (!file)
347 {
348 return 0;
349 }
350
351 buf = grub_zalloc(file->size + 2);
352 if (!buf)
353 {
354 grub_file_close(file);
355 return 0;
356 }
357
358 grub_file_read(file, buf, file->size);
359
360 for (start = buf; start; start = nextline)
361 {
362 nextline = ventoy_get_line(start);
363
364 while (ventoy_isspace(*start))
365 {
366 start++;
367 }
368
369 if (grub_strncmp(start, "initrd", 6) != 0)
370 {
371 continue;
372 }
373
374 start += 6;
375 while (*start && (!ventoy_isspace(*start)))
376 {
377 start++;
378 }
379
380 while (ventoy_isspace(*start))
381 {
382 start++;
383 }
384
385 while (*start)
386 {
387 img = grub_zalloc(sizeof(initrd_info));
388 if (!img)
389 {
390 break;
391 }
392
393 dollar = 0;
394 for (i = 0; i < 255 && (0 == ventoy_is_word_end(*start)); i++)
395 {
396 img->name[i] = *start++;
397 if (img->name[i] == '$')
398 {
399 dollar = 1;
400 }
401 }
402
403 if (dollar == 1 || ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
404 {
405 grub_free(img);
406 }
407 else
408 {
409 if (g_initrd_img_list)
410 {
411 img->prev = g_initrd_img_tail;
412 g_initrd_img_tail->next = img;
413 }
414 else
415 {
416 g_initrd_img_list = img;
417 }
418
419 g_initrd_img_tail = img;
420 g_initrd_img_count++;
421 }
422
423 if (*start == ' ' || *start == '\t')
424 {
425 while (ventoy_isspace(*start))
426 {
427 start++;
428 }
429 }
430 else
431 {
432 break;
433 }
434 }
435 }
436
437 grub_free(buf);
438 grub_file_close(file);
439
440 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
441 }
442
443 static int ventoy_grub_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
444 {
445 char filePath[256];
446 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
447
448 (void)info;
449
450 debug("ventoy_grub_initrd_hook %s\n", filename);
451
452 if (NULL == grub_strstr(filename, ".cfg") &&
453 NULL == grub_strstr(filename, ".CFG") &&
454 NULL == grub_strstr(filename, ".conf"))
455 {
456 return 0;
457 }
458
459 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
460
461 grub_snprintf(filePath, sizeof(filePath) - 1, "%s%s", ctx->dir_prefix, filename);
462 ventoy_grub_cfg_initrd_collect(filePath);
463
464 return 0;
465 }
466
467 grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
468 {
469 grub_fs_t fs;
470 grub_device_t dev = NULL;
471 char *device_name = NULL;
472 ventoy_initrd_ctx ctx;
473
474 (void)ctxt;
475 (void)argc;
476
477 if (argc != 2)
478 {
479 return 0;
480 }
481
482 debug("grub initrd collect %s %s\n", args[0], args[1]);
483
484 if (grub_strcmp(args[0], "file") == 0)
485 {
486 return ventoy_grub_cfg_initrd_collect(args[1]);
487 }
488
489 device_name = grub_file_get_device_name(args[1]);
490 if (!device_name)
491 {
492 debug("failed to get device name %s\n", args[1]);
493 goto end;
494 }
495
496 dev = grub_device_open(device_name);
497 if (!dev)
498 {
499 debug("failed to open device %s\n", device_name);
500 goto end;
501 }
502
503 fs = grub_fs_probe(dev);
504 if (!fs)
505 {
506 debug("failed to probe fs %d\n", grub_errno);
507 goto end;
508 }
509
510 ctx.dir_prefix = args[1];
511 ctx.path_prefix = grub_strstr(args[1], device_name);
512 if (ctx.path_prefix)
513 {
514 ctx.path_prefix += grub_strlen(device_name) + 1;
515 }
516 else
517 {
518 ctx.path_prefix = args[1];
519 }
520
521 debug("ctx.path_prefix:<%s>\n", ctx.path_prefix);
522
523 fs->fs_dir(dev, ctx.path_prefix, ventoy_grub_initrd_hook, &ctx);
524
525 end:
526 check_free(device_name, grub_free);
527 check_free(dev, grub_device_close);
528
529
530 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
531 }
532
533 grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args)
534 {
535 initrd_info *img = NULL;
536
537 (void)ctxt;
538 (void)argc;
539
540 debug("ventoy_cmd_specify_initrd_file %s\n", args[0]);
541
542 img = grub_zalloc(sizeof(initrd_info));
543 if (!img)
544 {
545 return 1;
546 }
547
548 grub_strncpy(img->name, args[0], sizeof(img->name));
549 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
550 {
551 debug("%s is already exist\n", args[0]);
552 grub_free(img);
553 }
554 else
555 {
556 if (g_initrd_img_list)
557 {
558 img->prev = g_initrd_img_tail;
559 g_initrd_img_tail->next = img;
560 }
561 else
562 {
563 g_initrd_img_list = img;
564 }
565
566 g_initrd_img_tail = img;
567 g_initrd_img_count++;
568 }
569
570 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
571 }
572
573 static int ventoy_cpio_newc_get_int(char *value)
574 {
575 char buf[16] = {0};
576
577 grub_memcpy(buf, value, 8);
578 return (int)grub_strtoul(buf, NULL, 16);
579 }
580
581 static void ventoy_cpio_newc_fill_int(grub_uint32_t value, char *buf, int buflen)
582 {
583 int i;
584 int len;
585 char intbuf[32];
586
587 len = grub_snprintf(intbuf, sizeof(intbuf), "%x", value);
588
589 for (i = 0; i < buflen; i++)
590 {
591 buf[i] = '0';
592 }
593
594 if (len > buflen)
595 {
596 grub_printf("int buf len overflow %d %d\n", len, buflen);
597 }
598 else
599 {
600 grub_memcpy(buf + buflen - len, intbuf, len);
601 }
602 }
603
604 int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name)
605 {
606 int namelen = 0;
607 int headlen = 0;
608 static grub_uint32_t cpio_ino = 0xFFFFFFF0;
609 cpio_newc_header *cpio = (cpio_newc_header *)buf;
610
611 namelen = grub_strlen(name) + 1;
612 headlen = sizeof(cpio_newc_header) + namelen;
613 headlen = ventoy_align(headlen, 4);
614
615 grub_memset(cpio, '0', sizeof(cpio_newc_header));
616 grub_memset(cpio + 1, 0, headlen - sizeof(cpio_newc_header));
617
618 grub_memcpy(cpio->c_magic, "070701", 6);
619 ventoy_cpio_newc_fill_int(cpio_ino--, cpio->c_ino, 8);
620 ventoy_cpio_newc_fill_int(0100777, cpio->c_mode, 8);
621 ventoy_cpio_newc_fill_int(1, cpio->c_nlink, 8);
622 ventoy_cpio_newc_fill_int(filesize, cpio->c_filesize, 8);
623 ventoy_cpio_newc_fill_int(namelen, cpio->c_namesize, 8);
624 grub_memcpy(cpio + 1, name, namelen);
625
626 if (filedata)
627 {
628 grub_memcpy((char *)cpio + headlen, filedata, filesize);
629 }
630
631 return headlen;
632 }
633
634 static grub_uint32_t ventoy_linux_get_virt_chunk_count(void)
635 {
636 grub_uint32_t count = g_valid_initrd_count;
637
638 if (g_conf_replace_offset > 0)
639 {
640 count++;
641 }
642
643 return count;
644 }
645
646 static grub_uint32_t ventoy_linux_get_virt_chunk_size(void)
647 {
648 grub_uint32_t size;
649
650 size = (sizeof(ventoy_virt_chunk) + g_ventoy_cpio_size) * g_valid_initrd_count;
651
652 if (g_conf_replace_offset > 0)
653 {
654 size += sizeof(ventoy_virt_chunk) + g_conf_replace_new_len_align;
655 }
656
657 return size;
658 }
659
660 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
661 {
662 int id = 0;
663 initrd_info *node;
664 grub_uint64_t sector;
665 grub_uint32_t offset;
666 grub_uint32_t cpio_secs;
667 grub_uint32_t initrd_secs;
668 char *override;
669 ventoy_virt_chunk *cur;
670 char name[32];
671
672 override = (char *)chain + chain->virt_chunk_offset;
673 sector = (isosize + 2047) / 2048;
674 cpio_secs = g_ventoy_cpio_size / 2048;
675
676 offset = ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk);
677 cur = (ventoy_virt_chunk *)override;
678
679 for (node = g_initrd_img_list; node; node = node->next)
680 {
681 if (node->size == 0)
682 {
683 continue;
684 }
685
686 initrd_secs = (grub_uint32_t)((node->size + 2047) / 2048);
687
688 cur->mem_sector_start = sector;
689 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
690 cur->mem_sector_offset = offset;
691 cur->remap_sector_start = cur->mem_sector_end;
692 cur->remap_sector_end = cur->remap_sector_start + initrd_secs;
693 cur->org_sector_start = (grub_uint32_t)(node->offset / 2048);
694
695 grub_memcpy(g_ventoy_runtime_buf, &chain->os_param, sizeof(ventoy_os_param));
696
697 grub_memset(name, 0, 16);
698 grub_snprintf(name, sizeof(name), "initrd%03d", ++id);
699
700 grub_memcpy(g_ventoy_initrd_head + 1, name, 16);
701 ventoy_cpio_newc_fill_int((grub_uint32_t)node->size, g_ventoy_initrd_head->c_filesize, 8);
702
703 grub_memcpy(override + offset, g_ventoy_cpio_buf, g_ventoy_cpio_size);
704
705 chain->virt_img_size_in_bytes += g_ventoy_cpio_size + initrd_secs * 2048;
706
707 offset += g_ventoy_cpio_size;
708 sector += cpio_secs + initrd_secs;
709 cur++;
710 }
711
712 if (g_conf_replace_offset > 0)
713 {
714 cpio_secs = g_conf_replace_new_len_align / 2048;
715
716 cur->mem_sector_start = sector;
717 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
718 cur->mem_sector_offset = offset;
719 cur->remap_sector_start = 0;
720 cur->remap_sector_end = 0;
721 cur->org_sector_start = 0;
722
723 grub_memcpy(override + offset, g_conf_replace_new_buf, g_conf_replace_new_len);
724
725 chain->virt_img_size_in_bytes += g_conf_replace_new_len_align;
726
727 offset += g_conf_replace_new_len_align;
728 sector += cpio_secs;
729 cur++;
730 }
731
732 return;
733 }
734
735 static grub_uint32_t ventoy_linux_get_override_chunk_count(void)
736 {
737 grub_uint32_t count = g_valid_initrd_count;
738
739 if (g_conf_replace_offset > 0)
740 {
741 count++;
742 }
743
744 if (g_svd_replace_offset > 0)
745 {
746 count++;
747 }
748
749 return count;
750 }
751
752 static grub_uint32_t ventoy_linux_get_override_chunk_size(void)
753 {
754 int count = g_valid_initrd_count;
755
756 if (g_conf_replace_offset > 0)
757 {
758 count++;
759 }
760
761 if (g_svd_replace_offset > 0)
762 {
763 count++;
764 }
765
766 return sizeof(ventoy_override_chunk) * count;
767 }
768
769 static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override)
770 {
771 initrd_info *node;
772 grub_uint32_t mod;
773 grub_uint32_t newlen;
774 grub_uint64_t sector;
775 ventoy_override_chunk *cur;
776 ventoy_iso9660_override *dirent;
777 ventoy_udf_override *udf;
778
779 sector = (isosize + 2047) / 2048;
780
781 cur = (ventoy_override_chunk *)override;
782 for (node = g_initrd_img_list; node; node = node->next)
783 {
784 if (node->size == 0)
785 {
786 continue;
787 }
788
789 newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
790 mod = newlen % 4;
791 if (mod > 0)
792 {
793 newlen += 4 - mod; /* cpio must align with 4 */
794 }
795
796 if (node->iso_type == 0)
797 {
798 dirent = (ventoy_iso9660_override *)node->override_data;
799
800 node->override_length = sizeof(ventoy_iso9660_override);
801 dirent->first_sector = (grub_uint32_t)sector;
802 dirent->size = newlen;
803 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
804 dirent->size_be = grub_swap_bytes32(dirent->size);
805
806 sector += (dirent->size + 2047) / 2048;
807 }
808 else
809 {
810 udf = (ventoy_udf_override *)node->override_data;
811
812 node->override_length = sizeof(ventoy_udf_override);
813 udf->length = newlen;
814 udf->position = (grub_uint32_t)sector - node->udf_start_block;
815
816 sector += (udf->length + 2047) / 2048;
817 }
818
819 cur->img_offset = node->override_offset;
820 cur->override_size = node->override_length;
821 grub_memcpy(cur->override_data, node->override_data, cur->override_size);
822 cur++;
823 }
824
825 if (g_conf_replace_offset > 0)
826 {
827 cur->img_offset = g_conf_replace_offset;
828 cur->override_size = sizeof(ventoy_iso9660_override);
829
830 newlen = (grub_uint32_t)(g_conf_replace_new_len);
831
832 dirent = (ventoy_iso9660_override *)cur->override_data;
833 dirent->first_sector = (grub_uint32_t)sector;
834 dirent->size = newlen;
835 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
836 dirent->size_be = grub_swap_bytes32(dirent->size);
837
838 sector += (dirent->size + 2047) / 2048;
839 cur++;
840 }
841
842 if (g_svd_replace_offset > 0)
843 {
844 cur->img_offset = g_svd_replace_offset;
845 cur->override_size = 1;
846 cur->override_data[0] = 0xFF;
847 cur++;
848 }
849
850 return;
851 }
852
853 grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
854 {
855 char buf[32] = {0};
856
857 (void)ctxt;
858 (void)argc;
859 (void)args;
860
861 if (argc == 1)
862 {
863 grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count);
864 grub_env_set(args[0], buf);
865 }
866
867 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
868 }
869
870 grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
871 {
872 char buf[32] = {0};
873
874 (void)ctxt;
875 (void)argc;
876 (void)args;
877
878 if (argc == 1)
879 {
880 grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count);
881 grub_env_set(args[0], buf);
882 }
883
884 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
885 }
886
887 static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt)
888 {
889 int data;
890 int filtbysize = 1;
891 int sizefilt = 0;
892 grub_file_t file;
893 initrd_info *node;
894
895 debug("ventoy_linux_locate_initrd %d\n", filt);
896
897 g_valid_initrd_count = 0;
898
899 if (grub_env_get("INITRD_NO_SIZE_FILT"))
900 {
901 filtbysize = 0;
902 }
903
904 for (node = g_initrd_img_list; node; node = node->next)
905 {
906 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name);
907 if (!file)
908 {
909 continue;
910 }
911
912 debug("file <%s> size:%d\n", node->name, (int)file->size);
913
914 /* initrd file too small */
915 if (filtbysize
916 && (NULL == grub_strstr(node->name, "minirt.gz"))
917 && (NULL == grub_strstr(node->name, "initrd.xz"))
918 )
919 {
920 if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048)
921 {
922 debug("file size too small %d\n", (int)g_ventoy_cpio_size);
923 grub_file_close(file);
924 sizefilt++;
925 continue;
926 }
927 }
928
929 if (grub_strcmp(file->fs->name, "iso9660") == 0)
930 {
931 node->iso_type = 0;
932 node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
933
934 grub_file_read(file, &data, 1); // just read for hook trigger
935 node->offset = grub_iso9660_get_last_read_pos(file);
936 }
937 else
938 {
939 /* TBD */
940 }
941
942 node->size = file->size;
943 g_valid_initrd_count++;
944
945 grub_file_close(file);
946 }
947
948 *filtcnt = sizefilt;
949
950 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
951 }
952
953
954 grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args)
955 {
956 int index = 0;
957 char buf[32];
958 initrd_info *node = NULL;
959
960 (void)ctxt;
961 (void)argc;
962 (void)args;
963
964 if (argc != 1)
965 {
966 return 1;
967 }
968
969 if (g_initrd_img_count == 1)
970 {
971 ventoy_set_env(args[0], "0");
972 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
973 }
974
975 for (node = g_initrd_img_list; node; node = node->next)
976 {
977 if (node->size <= 0)
978 {
979 continue;
980 }
981
982 if (grub_strstr(node->name, "ucode") || grub_strstr(node->name, "-firmware"))
983 {
984 index++;
985 continue;
986 }
987
988 grub_snprintf(buf, sizeof(buf), "%d", index);
989 ventoy_set_env(args[0], buf);
990 break;
991 }
992
993 debug("main initrd index:%d\n", index);
994
995 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
996 }
997
998 grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
999 {
1000 int sizefilt = 0;
1001
1002 (void)ctxt;
1003 (void)argc;
1004 (void)args;
1005
1006 ventoy_linux_locate_initrd(1, &sizefilt);
1007
1008 if (g_valid_initrd_count == 0 && sizefilt > 0)
1009 {
1010 ventoy_linux_locate_initrd(0, &sizefilt);
1011 }
1012
1013 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1014 }
1015
1016 static int ventoy_cpio_busybox64(cpio_newc_header *head, const char *file)
1017 {
1018 char *name;
1019 int namelen;
1020 int offset;
1021 int count = 0;
1022 char filepath[128];
1023
1024 grub_snprintf(filepath, sizeof(filepath), "ventoy/busybox/%s", file);
1025
1026 name = (char *)(head + 1);
1027 while (name[0] && count < 2)
1028 {
1029 if (grub_strcmp(name, "ventoy/busybox/ash") == 0)
1030 {
1031 grub_memcpy(name, "ventoy/busybox/32h", 18);
1032 count++;
1033 }
1034 else if (grub_strcmp(name, filepath) == 0)
1035 {
1036 grub_memcpy(name, "ventoy/busybox/ash", 18);
1037 count++;
1038 }
1039
1040 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1041 offset = sizeof(cpio_newc_header) + namelen;
1042 offset = ventoy_align(offset, 4);
1043 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1044 offset = ventoy_align(offset, 4);
1045
1046 head = (cpio_newc_header *)((char *)head + offset);
1047 name = (char *)(head + 1);
1048 }
1049
1050 return 0;
1051 }
1052
1053
1054 grub_err_t ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt, int argc, char **args)
1055 {
1056 (void)ctxt;
1057 (void)argc;
1058 (void)args;
1059
1060 debug("ventoy_cmd_busybox_64 %d\n", argc);
1061 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, args[0]);
1062 return 0;
1063 }
1064
1065 grub_err_t ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt, int argc, char **args)
1066 {
1067 int i;
1068 grub_file_t file;
1069 char buf[16];
1070
1071 (void)ctxt;
1072 (void)argc;
1073
1074 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1075 if (!file)
1076 {
1077 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1078 }
1079
1080 for (i = 0; i < 10; i++)
1081 {
1082 buf[0] = 0;
1083 grub_file_seek(file, (17 + i) * 2048);
1084 grub_file_read(file, buf, 16);
1085
1086 if (buf[0] == 2 && grub_strncmp(buf + 1, "CD001", 5) == 0)
1087 {
1088 debug("Find SVD at VD %d\n", i);
1089 g_svd_replace_offset = (17 + i) * 2048;
1090 break;
1091 }
1092 }
1093
1094 if (i >= 10)
1095 {
1096 debug("SVD not found %d\n", (int)g_svd_replace_offset);
1097 }
1098
1099 grub_file_close(file);
1100
1101 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1102 }
1103
1104 grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1105 {
1106 int i;
1107 int rc;
1108 char *pos = NULL;
1109 char *template_file = NULL;
1110 char *template_buf = NULL;
1111 char *persistent_buf = NULL;
1112 char *injection_buf = NULL;
1113 dud *dudnode = NULL;
1114 char tmpname[128];
1115 const char *injection_file = NULL;
1116 grub_uint8_t *buf = NULL;
1117 grub_uint32_t mod;
1118 grub_uint32_t headlen;
1119 grub_uint32_t initrd_head_len;
1120 grub_uint32_t padlen;
1121 grub_uint32_t img_chunk_size;
1122 grub_uint32_t template_size = 0;
1123 grub_uint32_t persistent_size = 0;
1124 grub_uint32_t injection_size = 0;
1125 grub_uint32_t dud_size = 0;
1126 grub_file_t file;
1127 grub_file_t archfile;
1128 grub_file_t tmpfile;
1129 ventoy_img_chunk_list chunk_list;
1130
1131 (void)ctxt;
1132 (void)argc;
1133
1134 if (argc != 4)
1135 {
1136 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name);
1137 }
1138
1139 if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0)
1140 {
1141 return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n");
1142 }
1143
1144 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1145
1146 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_COMM_CPIO);
1147 if (!file)
1148 {
1149 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_COMM_CPIO);
1150 }
1151
1152 archfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_ARCH_CPIO);
1153 if (!archfile)
1154 {
1155 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_ARCH_CPIO);
1156 grub_file_close(file);
1157 }
1158
1159 debug("load %s %s success\n", VTOY_COMM_CPIO, VTOY_ARCH_CPIO);
1160
1161 if (g_ventoy_cpio_buf)
1162 {
1163 grub_free(g_ventoy_cpio_buf);
1164 g_ventoy_cpio_buf = NULL;
1165 g_ventoy_cpio_size = 0;
1166 }
1167
1168 rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list);
1169 if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
1170 {
1171 persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1172 persistent_buf = (char *)(chunk_list.chunk);
1173 }
1174
1175 template_file = ventoy_plugin_get_cur_install_template(args[1]);
1176 if (template_file)
1177 {
1178 debug("auto install template: <%s>\n", template_file);
1179 tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], template_file);
1180 if (tmpfile)
1181 {
1182 debug("auto install script size %d\n", (int)tmpfile->size);
1183 template_size = tmpfile->size;
1184 template_buf = grub_malloc(template_size);
1185 if (template_buf)
1186 {
1187 grub_file_read(tmpfile, template_buf, template_size);
1188 }
1189
1190 grub_file_close(tmpfile);
1191 }
1192 else
1193 {
1194 debug("Failed to open install script %s%s\n", args[2], template_file);
1195 }
1196 }
1197 else
1198 {
1199 debug("auto install script skipped or not configed %s\n", args[1]);
1200 }
1201
1202 injection_file = ventoy_plugin_get_injection(args[1]);
1203 if (injection_file)
1204 {
1205 debug("injection archive: <%s>\n", injection_file);
1206 tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], injection_file);
1207 if (tmpfile)
1208 {
1209 debug("injection archive size:%d\n", (int)tmpfile->size);
1210 injection_size = tmpfile->size;
1211 injection_buf = grub_malloc(injection_size);
1212 if (injection_buf)
1213 {
1214 grub_file_read(tmpfile, injection_buf, injection_size);
1215 }
1216
1217 grub_file_close(tmpfile);
1218 }
1219 else
1220 {
1221 debug("Failed to open injection archive %s%s\n", args[2], injection_file);
1222 }
1223 }
1224 else
1225 {
1226 debug("injection not configed %s\n", args[1]);
1227 }
1228
1229 dudnode = ventoy_plugin_find_dud(args[1]);
1230 if (dudnode)
1231 {
1232 debug("dud file: <%d>\n", dudnode->dudnum);
1233 ventoy_plugin_load_dud(dudnode, args[2]);
1234 for (i = 0; i < dudnode->dudnum; i++)
1235 {
1236 if (dudnode->files[i].size > 0)
1237 {
1238 dud_size += dudnode->files[i].size + sizeof(cpio_newc_header);
1239 }
1240 }
1241 }
1242 else
1243 {
1244 debug("dud not configed %s\n", args[1]);
1245 }
1246
1247 g_ventoy_cpio_buf = grub_malloc(file->size + archfile->size + 40960 + template_size +
1248 persistent_size + injection_size + dud_size + img_chunk_size);
1249 if (NULL == g_ventoy_cpio_buf)
1250 {
1251 grub_file_close(file);
1252 grub_file_close(archfile);
1253 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size);
1254 }
1255
1256 grub_file_read(file, g_ventoy_cpio_buf, file->size);
1257 buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4);
1258 while (*((grub_uint32_t *)buf) != 0x37303730)
1259 {
1260 buf -= 4;
1261 }
1262
1263 grub_file_read(archfile, buf, archfile->size);
1264 buf += (archfile->size - 4);
1265 while (*((grub_uint32_t *)buf) != 0x37303730)
1266 {
1267 buf -= 4;
1268 }
1269
1270 /* get initrd head len */
1271 initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx");
1272
1273 /* step1: insert image chunk data to cpio */
1274 headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map");
1275 buf += headlen + ventoy_align(img_chunk_size, 4);
1276
1277 if (template_buf)
1278 {
1279 headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall");
1280 buf += headlen + ventoy_align(template_size, 4);
1281 }
1282
1283 if (persistent_size > 0 && persistent_buf)
1284 {
1285 headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
1286 buf += headlen + ventoy_align(persistent_size, 4);
1287
1288 grub_free(persistent_buf);
1289 persistent_buf = NULL;
1290 }
1291
1292 if (injection_size > 0 && injection_buf)
1293 {
1294 headlen = ventoy_cpio_newc_fill_head(buf, injection_size, injection_buf, "ventoy/ventoy_injection");
1295 buf += headlen + ventoy_align(injection_size, 4);
1296
1297 grub_free(injection_buf);
1298 injection_buf = NULL;
1299 }
1300
1301 if (dud_size > 0)
1302 {
1303 for (i = 0; i < dudnode->dudnum; i++)
1304 {
1305 pos = grub_strrchr(dudnode->dudpath[i].path, '.');
1306 grub_snprintf(tmpname, sizeof(tmpname), "ventoy/ventoy_dud%d%s", i, (pos ? pos : ".iso"));
1307 dud_size = dudnode->files[i].size;
1308 headlen = ventoy_cpio_newc_fill_head(buf, dud_size, dudnode->files[i].buf, tmpname);
1309 buf += headlen + ventoy_align(dud_size, 4);
1310 }
1311 }
1312
1313 /* step2: insert os param to cpio */
1314 headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
1315 padlen = sizeof(ventoy_os_param);
1316 g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len;
1317 mod = g_ventoy_cpio_size % 2048;
1318 if (mod)
1319 {
1320 g_ventoy_cpio_size += 2048 - mod;
1321 padlen += 2048 - mod;
1322 }
1323
1324 /* update os param data size, the data will be updated before chain boot */
1325 ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8);
1326 g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen;
1327
1328 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1329 g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen);
1330 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx");
1331
1332 grub_file_close(file);
1333 grub_file_close(archfile);
1334
1335 if (grub_strcmp(args[3], "busybox=64") == 0)
1336 {
1337 debug("cpio busybox proc %s\n", args[3]);
1338 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "64h");
1339 }
1340 else if (grub_strcmp(args[3], "busybox=a64") == 0)
1341 {
1342 debug("cpio busybox proc %s\n", args[3]);
1343 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "a64");
1344 }
1345 else if (grub_strcmp(args[3], "busybox=m64") == 0)
1346 {
1347 debug("cpio busybox proc %s\n", args[3]);
1348 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "m64");
1349 }
1350
1351 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1352 }
1353
1354 grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1355 {
1356 int mod;
1357 int bufsize;
1358 int namelen;
1359 int offset;
1360 char *name;
1361 grub_uint8_t *bufend;
1362 cpio_newc_header *head;
1363 grub_file_t file;
1364 char value[64];
1365 const grub_uint8_t trailler[124] = {
1366 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1367 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1368 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1369 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1370 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1371 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1372 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1373 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1374 };
1375
1376 (void)ctxt;
1377 (void)argc;
1378
1379 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], args[1]);
1380 if (!file)
1381 {
1382 return 1;
1383 }
1384
1385 grub_memset(g_ventoy_runtime_buf, 0, sizeof(ventoy_os_param));
1386 ventoy_fill_os_param(file, (ventoy_os_param *)g_ventoy_runtime_buf);
1387
1388 grub_file_close(file);
1389
1390 grub_memcpy(g_ventoy_initrd_head, trailler, sizeof(trailler));
1391 bufend = (grub_uint8_t *)g_ventoy_initrd_head + sizeof(trailler);
1392
1393 bufsize = (int)(bufend - g_ventoy_cpio_buf);
1394 mod = bufsize % 512;
1395 if (mod)
1396 {
1397 grub_memset(bufend, 0, 512 - mod);
1398 bufsize += 512 - mod;
1399 }
1400
1401 if (argc > 1 && grub_strcmp(args[2], "noinit") == 0)
1402 {
1403 head = (cpio_newc_header *)g_ventoy_cpio_buf;
1404 name = (char *)(head + 1);
1405
1406 while (grub_strcmp(name, "TRAILER!!!"))
1407 {
1408 if (grub_strcmp(name, "init") == 0)
1409 {
1410 grub_memcpy(name, "xxxx", 4);
1411 }
1412 else if (grub_strcmp(name, "linuxrc") == 0)
1413 {
1414 grub_memcpy(name, "vtoyxrc", 7);
1415 }
1416 else if (grub_strcmp(name, "sbin") == 0)
1417 {
1418 grub_memcpy(name, "vtoy", 4);
1419 }
1420 else if (grub_strcmp(name, "sbin/init") == 0)
1421 {
1422 grub_memcpy(name, "vtoy/vtoy", 9);
1423 }
1424
1425 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1426 offset = sizeof(cpio_newc_header) + namelen;
1427 offset = ventoy_align(offset, 4);
1428 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1429 offset = ventoy_align(offset, 4);
1430
1431 head = (cpio_newc_header *)((char *)head + offset);
1432 name = (char *)(head + 1);
1433 }
1434 }
1435
1436 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)g_ventoy_cpio_buf);
1437 ventoy_set_env("ventoy_cpio_addr", value);
1438 grub_snprintf(value, sizeof(value), "%d", bufsize);
1439 ventoy_set_env("ventoy_cpio_size", value);
1440
1441 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1442 }
1443
1444
1445 grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1446 {
1447 int ventoy_compatible = 0;
1448 grub_uint32_t size = 0;
1449 grub_uint64_t isosize = 0;
1450 grub_uint32_t boot_catlog = 0;
1451 grub_uint32_t img_chunk_size = 0;
1452 grub_uint32_t override_count = 0;
1453 grub_uint32_t override_size = 0;
1454 grub_uint32_t virt_chunk_count = 0;
1455 grub_uint32_t virt_chunk_size = 0;
1456 grub_file_t file;
1457 grub_disk_t disk;
1458 const char *pLastChain = NULL;
1459 const char *compatible;
1460 ventoy_chain_head *chain;
1461 char envbuf[64];
1462
1463 (void)ctxt;
1464 (void)argc;
1465
1466 compatible = grub_env_get("ventoy_compatible");
1467 if (compatible && compatible[0] == 'Y')
1468 {
1469 ventoy_compatible = 1;
1470 }
1471
1472 if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL))
1473 {
1474 grub_printf("ventoy not ready\n");
1475 return 1;
1476 }
1477
1478 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1479 if (!file)
1480 {
1481 return 1;
1482 }
1483
1484 isosize = file->size;
1485
1486 boot_catlog = ventoy_get_iso_boot_catlog(file);
1487 if (boot_catlog)
1488 {
1489 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1490 {
1491 grub_env_set("LoadIsoEfiDriver", "on");
1492 }
1493 }
1494 else
1495 {
1496 if (ventoy_is_efi_os())
1497 {
1498 grub_env_set("LoadIsoEfiDriver", "on");
1499 }
1500 else
1501 {
1502 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1503 }
1504 }
1505
1506 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1507
1508 override_count = ventoy_linux_get_override_chunk_count();
1509 virt_chunk_count = ventoy_linux_get_virt_chunk_count();
1510
1511 if (ventoy_compatible)
1512 {
1513 size = sizeof(ventoy_chain_head) + img_chunk_size;
1514 }
1515 else
1516 {
1517 override_size = ventoy_linux_get_override_chunk_size();
1518 virt_chunk_size = ventoy_linux_get_virt_chunk_size();
1519 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1520 }
1521
1522 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1523 if (pLastChain)
1524 {
1525 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1526 if (chain)
1527 {
1528 debug("free last chain memory %p\n", chain);
1529 grub_free(chain);
1530 }
1531 }
1532
1533 chain = grub_malloc(size);
1534 if (!chain)
1535 {
1536 grub_printf("Failed to alloc chain memory size %u\n", size);
1537 grub_file_close(file);
1538 return 1;
1539 }
1540
1541 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1542 grub_env_set("vtoy_chain_mem_addr", envbuf);
1543 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1544 grub_env_set("vtoy_chain_mem_size", envbuf);
1545
1546 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1547
1548 /* part 1: os parameter */
1549 g_ventoy_chain_type = ventoy_chain_linux;
1550 ventoy_fill_os_param(file, &(chain->os_param));
1551
1552 /* part 2: chain head */
1553 disk = file->device->disk;
1554 chain->disk_drive = disk->id;
1555 chain->disk_sector_size = (1 << disk->log_sector_size);
1556 chain->real_img_size_in_bytes = file->size;
1557 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1558 chain->boot_catalog = boot_catlog;
1559
1560 if (!ventoy_is_efi_os())
1561 {
1562 grub_file_seek(file, boot_catlog * 2048);
1563 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1564 }
1565
1566 /* part 3: image chunk */
1567 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1568 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1569 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1570
1571 if (ventoy_compatible)
1572 {
1573 return 0;
1574 }
1575
1576 /* part 4: override chunk */
1577 if (override_count > 0)
1578 {
1579 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1580 chain->override_chunk_num = override_count;
1581 ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
1582 }
1583
1584 /* part 5: virt chunk */
1585 if (virt_chunk_count > 0)
1586 {
1587 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1588 chain->virt_chunk_num = virt_chunk_count;
1589 ventoy_linux_fill_virt_data(isosize, chain);
1590 }
1591
1592 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1593 }
1594