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