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