]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
560355ab745aa5aaddd9fd262d4bcd2bea08975d
[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 initrd_info *node;
695 grub_uint64_t sector;
696 grub_uint32_t offset;
697 grub_uint32_t cpio_secs;
698 grub_uint32_t initrd_secs;
699 char *override;
700 ventoy_virt_chunk *cur;
701 char name[32];
702
703 override = (char *)chain + chain->virt_chunk_offset;
704 sector = (isosize + 2047) / 2048;
705 cpio_secs = g_ventoy_cpio_size / 2048;
706
707 offset = ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk);
708 cur = (ventoy_virt_chunk *)override;
709
710 for (node = g_initrd_img_list; node; node = node->next)
711 {
712 if (node->size == 0)
713 {
714 continue;
715 }
716
717 initrd_secs = (grub_uint32_t)((node->size + 2047) / 2048);
718
719 cur->mem_sector_start = sector;
720 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
721 cur->mem_sector_offset = offset;
722 cur->remap_sector_start = cur->mem_sector_end;
723 cur->remap_sector_end = cur->remap_sector_start + initrd_secs;
724 cur->org_sector_start = (grub_uint32_t)(node->offset / 2048);
725
726 grub_memcpy(g_ventoy_runtime_buf, &chain->os_param, sizeof(ventoy_os_param));
727
728 grub_memset(name, 0, 16);
729 grub_snprintf(name, sizeof(name), "initrd%03d", ++id);
730
731 grub_memcpy(g_ventoy_initrd_head + 1, name, 16);
732 ventoy_cpio_newc_fill_int((grub_uint32_t)node->size, g_ventoy_initrd_head->c_filesize, 8);
733
734 grub_memcpy(override + offset, g_ventoy_cpio_buf, g_ventoy_cpio_size);
735
736 chain->virt_img_size_in_bytes += g_ventoy_cpio_size + initrd_secs * 2048;
737
738 offset += g_ventoy_cpio_size;
739 sector += cpio_secs + initrd_secs;
740 cur++;
741 }
742
743 /* Lenovo EasyStartup need an addional sector for boundary check */
744 if (g_append_ext_sector > 0)
745 {
746 cpio_secs = VTOY_APPEND_EXT_SIZE / 2048;
747
748 cur->mem_sector_start = sector;
749 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
750 cur->mem_sector_offset = offset;
751 cur->remap_sector_start = 0;
752 cur->remap_sector_end = 0;
753 cur->org_sector_start = 0;
754
755 grub_memset(override + offset, 0, VTOY_APPEND_EXT_SIZE);
756
757 chain->virt_img_size_in_bytes += VTOY_APPEND_EXT_SIZE;
758
759 offset += VTOY_APPEND_EXT_SIZE;
760 sector += cpio_secs;
761 cur++;
762 }
763
764 if (g_conf_replace_offset > 0)
765 {
766 cpio_secs = g_conf_replace_new_len_align / 2048;
767
768 cur->mem_sector_start = sector;
769 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
770 cur->mem_sector_offset = offset;
771 cur->remap_sector_start = 0;
772 cur->remap_sector_end = 0;
773 cur->org_sector_start = 0;
774
775 grub_memcpy(override + offset, g_conf_replace_new_buf, g_conf_replace_new_len);
776
777 chain->virt_img_size_in_bytes += g_conf_replace_new_len_align;
778
779 offset += g_conf_replace_new_len_align;
780 sector += cpio_secs;
781 cur++;
782 }
783
784 return;
785 }
786
787 static grub_uint32_t ventoy_linux_get_override_chunk_count(void)
788 {
789 grub_uint32_t count = g_valid_initrd_count;
790
791 if (g_conf_replace_offset > 0)
792 {
793 count++;
794 }
795
796 if (g_svd_replace_offset > 0)
797 {
798 count++;
799 }
800
801 return count;
802 }
803
804 static grub_uint32_t ventoy_linux_get_override_chunk_size(void)
805 {
806 int count = g_valid_initrd_count;
807
808 if (g_conf_replace_offset > 0)
809 {
810 count++;
811 }
812
813 if (g_svd_replace_offset > 0)
814 {
815 count++;
816 }
817
818 return sizeof(ventoy_override_chunk) * count;
819 }
820
821 static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override)
822 {
823 initrd_info *node;
824 grub_uint32_t mod;
825 grub_uint32_t newlen;
826 grub_uint64_t sector;
827 ventoy_override_chunk *cur;
828 ventoy_iso9660_override *dirent;
829 ventoy_udf_override *udf;
830
831 sector = (isosize + 2047) / 2048;
832
833 cur = (ventoy_override_chunk *)override;
834 for (node = g_initrd_img_list; node; node = node->next)
835 {
836 if (node->size == 0)
837 {
838 continue;
839 }
840
841 newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
842 mod = newlen % 4;
843 if (mod > 0)
844 {
845 newlen += 4 - mod; /* cpio must align with 4 */
846 }
847
848 if (node->iso_type == 0)
849 {
850 dirent = (ventoy_iso9660_override *)node->override_data;
851
852 node->override_length = sizeof(ventoy_iso9660_override);
853 dirent->first_sector = (grub_uint32_t)sector;
854 dirent->size = newlen;
855 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
856 dirent->size_be = grub_swap_bytes32(dirent->size);
857
858 sector += (dirent->size + 2047) / 2048;
859 }
860 else
861 {
862 udf = (ventoy_udf_override *)node->override_data;
863
864 node->override_length = sizeof(ventoy_udf_override);
865 udf->length = newlen;
866 udf->position = (grub_uint32_t)sector - node->udf_start_block;
867
868 sector += (udf->length + 2047) / 2048;
869 }
870
871 cur->img_offset = node->override_offset;
872 cur->override_size = node->override_length;
873 grub_memcpy(cur->override_data, node->override_data, cur->override_size);
874 cur++;
875 }
876
877 if (g_conf_replace_offset > 0)
878 {
879 cur->img_offset = g_conf_replace_offset;
880 cur->override_size = sizeof(ventoy_iso9660_override);
881
882 newlen = (grub_uint32_t)(g_conf_replace_new_len);
883
884 dirent = (ventoy_iso9660_override *)cur->override_data;
885 dirent->first_sector = (grub_uint32_t)sector;
886 dirent->size = newlen;
887 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
888 dirent->size_be = grub_swap_bytes32(dirent->size);
889
890 sector += (dirent->size + 2047) / 2048;
891 cur++;
892 }
893
894 if (g_svd_replace_offset > 0)
895 {
896 cur->img_offset = g_svd_replace_offset;
897 cur->override_size = 1;
898 cur->override_data[0] = 0xFF;
899 cur++;
900 }
901
902 return;
903 }
904
905 grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
906 {
907 char buf[32] = {0};
908
909 (void)ctxt;
910 (void)argc;
911 (void)args;
912
913 if (argc == 1)
914 {
915 grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count);
916 grub_env_set(args[0], buf);
917 }
918
919 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
920 }
921
922 grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
923 {
924 char buf[32] = {0};
925
926 (void)ctxt;
927 (void)argc;
928 (void)args;
929
930 if (argc == 1)
931 {
932 grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count);
933 grub_env_set(args[0], buf);
934 }
935
936 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
937 }
938
939 static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt)
940 {
941 int data;
942 int filtbysize = 1;
943 int sizefilt = 0;
944 grub_file_t file;
945 initrd_info *node;
946
947 debug("ventoy_linux_locate_initrd %d\n", filt);
948
949 g_valid_initrd_count = 0;
950
951 if (grub_env_get("INITRD_NO_SIZE_FILT"))
952 {
953 filtbysize = 0;
954 }
955
956 for (node = g_initrd_img_list; node; node = node->next)
957 {
958 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name);
959 if (!file)
960 {
961 continue;
962 }
963
964 debug("file <%s> size:%d\n", node->name, (int)file->size);
965
966 /* initrd file too small */
967 if (filtbysize
968 && (NULL == grub_strstr(node->name, "minirt.gz"))
969 && (NULL == grub_strstr(node->name, "initrd.xz"))
970 )
971 {
972 if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048)
973 {
974 debug("file size too small %d\n", (int)g_ventoy_cpio_size);
975 grub_file_close(file);
976 sizefilt++;
977 continue;
978 }
979 }
980
981 if (grub_strcmp(file->fs->name, "iso9660") == 0)
982 {
983 node->iso_type = 0;
984 node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
985
986 grub_file_read(file, &data, 1); // just read for hook trigger
987 node->offset = grub_iso9660_get_last_read_pos(file);
988 }
989 else
990 {
991 /* TBD */
992 }
993
994 node->size = file->size;
995 g_valid_initrd_count++;
996
997 grub_file_close(file);
998 }
999
1000 *filtcnt = sizefilt;
1001
1002 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1003 }
1004
1005
1006 grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args)
1007 {
1008 int index = 0;
1009 char buf[32];
1010 initrd_info *node = NULL;
1011
1012 (void)ctxt;
1013 (void)argc;
1014 (void)args;
1015
1016 if (argc != 1)
1017 {
1018 return 1;
1019 }
1020
1021 if (g_initrd_img_count == 1)
1022 {
1023 ventoy_set_env(args[0], "0");
1024 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1025 }
1026
1027 for (node = g_initrd_img_list; node; node = node->next)
1028 {
1029 if (node->size <= 0)
1030 {
1031 continue;
1032 }
1033
1034 if (grub_strstr(node->name, "ucode") || grub_strstr(node->name, "-firmware"))
1035 {
1036 index++;
1037 continue;
1038 }
1039
1040 grub_snprintf(buf, sizeof(buf), "%d", index);
1041 ventoy_set_env(args[0], buf);
1042 break;
1043 }
1044
1045 debug("main initrd index:%d\n", index);
1046
1047 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1048 }
1049
1050 grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
1051 {
1052 int sizefilt = 0;
1053
1054 (void)ctxt;
1055 (void)argc;
1056 (void)args;
1057
1058 ventoy_linux_locate_initrd(1, &sizefilt);
1059
1060 if (g_valid_initrd_count == 0 && sizefilt > 0)
1061 {
1062 ventoy_linux_locate_initrd(0, &sizefilt);
1063 }
1064
1065 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1066 }
1067
1068 static int ventoy_cpio_busybox64(cpio_newc_header *head, const char *file)
1069 {
1070 char *name;
1071 int namelen;
1072 int offset;
1073 int count = 0;
1074 char filepath[128];
1075
1076 grub_snprintf(filepath, sizeof(filepath), "ventoy/busybox/%s", file);
1077
1078 name = (char *)(head + 1);
1079 while (name[0] && count < 2)
1080 {
1081 if (grub_strcmp(name, "ventoy/busybox/ash") == 0)
1082 {
1083 grub_memcpy(name, "ventoy/busybox/32h", 18);
1084 count++;
1085 }
1086 else if (grub_strcmp(name, filepath) == 0)
1087 {
1088 grub_memcpy(name, "ventoy/busybox/ash", 18);
1089 count++;
1090 }
1091
1092 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1093 offset = sizeof(cpio_newc_header) + namelen;
1094 offset = ventoy_align(offset, 4);
1095 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1096 offset = ventoy_align(offset, 4);
1097
1098 head = (cpio_newc_header *)((char *)head + offset);
1099 name = (char *)(head + 1);
1100 }
1101
1102 return 0;
1103 }
1104
1105
1106 grub_err_t ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt, int argc, char **args)
1107 {
1108 (void)ctxt;
1109 (void)argc;
1110 (void)args;
1111
1112 debug("ventoy_cmd_busybox_64 %d\n", argc);
1113 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, args[0]);
1114 return 0;
1115 }
1116
1117 grub_err_t ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt, int argc, char **args)
1118 {
1119 int i;
1120 grub_file_t file;
1121 char buf[16];
1122
1123 (void)ctxt;
1124 (void)argc;
1125
1126 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1127 if (!file)
1128 {
1129 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1130 }
1131
1132 for (i = 0; i < 10; i++)
1133 {
1134 buf[0] = 0;
1135 grub_file_seek(file, (17 + i) * 2048);
1136 grub_file_read(file, buf, 16);
1137
1138 if (buf[0] == 2 && grub_strncmp(buf + 1, "CD001", 5) == 0)
1139 {
1140 debug("Find SVD at VD %d\n", i);
1141 g_svd_replace_offset = (17 + i) * 2048;
1142 break;
1143 }
1144 }
1145
1146 if (i >= 10)
1147 {
1148 debug("SVD not found %d\n", (int)g_svd_replace_offset);
1149 }
1150
1151 grub_file_close(file);
1152
1153 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1154 }
1155
1156 grub_err_t ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1157 {
1158 (void)ctxt;
1159 (void)argc;
1160 (void)args;
1161
1162 if (args[0][0] == '1')
1163 {
1164 g_append_ext_sector = 1;
1165 }
1166 else
1167 {
1168 g_append_ext_sector = 0;
1169 }
1170
1171 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1172 }
1173
1174 grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1175 {
1176 int i;
1177 int rc;
1178 char *pos = NULL;
1179 char *template_file = NULL;
1180 char *template_buf = NULL;
1181 char *persistent_buf = NULL;
1182 char *injection_buf = NULL;
1183 dud *dudnode = NULL;
1184 char tmpname[128];
1185 const char *injection_file = NULL;
1186 grub_uint8_t *buf = NULL;
1187 grub_uint32_t mod;
1188 grub_uint32_t headlen;
1189 grub_uint32_t initrd_head_len;
1190 grub_uint32_t padlen;
1191 grub_uint32_t img_chunk_size;
1192 grub_uint32_t template_size = 0;
1193 grub_uint32_t persistent_size = 0;
1194 grub_uint32_t injection_size = 0;
1195 grub_uint32_t dud_size = 0;
1196 grub_file_t file;
1197 grub_file_t archfile;
1198 grub_file_t tmpfile;
1199 ventoy_img_chunk_list chunk_list;
1200
1201 (void)ctxt;
1202 (void)argc;
1203
1204 if (argc != 4)
1205 {
1206 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name);
1207 }
1208
1209 if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0)
1210 {
1211 return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n");
1212 }
1213
1214 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1215
1216 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_COMM_CPIO);
1217 if (!file)
1218 {
1219 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_COMM_CPIO);
1220 }
1221
1222 archfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_ARCH_CPIO);
1223 if (!archfile)
1224 {
1225 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_ARCH_CPIO);
1226 grub_file_close(file);
1227 }
1228
1229 debug("load %s %s success\n", VTOY_COMM_CPIO, VTOY_ARCH_CPIO);
1230
1231 if (g_ventoy_cpio_buf)
1232 {
1233 grub_free(g_ventoy_cpio_buf);
1234 g_ventoy_cpio_buf = NULL;
1235 g_ventoy_cpio_size = 0;
1236 }
1237
1238 rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list);
1239 if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
1240 {
1241 persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1242 persistent_buf = (char *)(chunk_list.chunk);
1243 }
1244
1245 template_file = ventoy_plugin_get_cur_install_template(args[1]);
1246 if (template_file)
1247 {
1248 debug("auto install template: <%s>\n", template_file);
1249 tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], template_file);
1250 if (tmpfile)
1251 {
1252 debug("auto install script size %d\n", (int)tmpfile->size);
1253 template_size = tmpfile->size;
1254 template_buf = grub_malloc(template_size);
1255 if (template_buf)
1256 {
1257 grub_file_read(tmpfile, template_buf, template_size);
1258 }
1259
1260 grub_file_close(tmpfile);
1261 }
1262 else
1263 {
1264 debug("Failed to open install script %s%s\n", args[2], template_file);
1265 }
1266 }
1267 else
1268 {
1269 debug("auto install script skipped or not configed %s\n", args[1]);
1270 }
1271
1272 injection_file = ventoy_plugin_get_injection(args[1]);
1273 if (injection_file)
1274 {
1275 debug("injection archive: <%s>\n", injection_file);
1276 tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], injection_file);
1277 if (tmpfile)
1278 {
1279 debug("injection archive size:%d\n", (int)tmpfile->size);
1280 injection_size = tmpfile->size;
1281 injection_buf = grub_malloc(injection_size);
1282 if (injection_buf)
1283 {
1284 grub_file_read(tmpfile, injection_buf, injection_size);
1285 }
1286
1287 grub_file_close(tmpfile);
1288 }
1289 else
1290 {
1291 debug("Failed to open injection archive %s%s\n", args[2], injection_file);
1292 }
1293 }
1294 else
1295 {
1296 debug("injection not configed %s\n", args[1]);
1297 }
1298
1299 dudnode = ventoy_plugin_find_dud(args[1]);
1300 if (dudnode)
1301 {
1302 debug("dud file: <%d>\n", dudnode->dudnum);
1303 ventoy_plugin_load_dud(dudnode, args[2]);
1304 for (i = 0; i < dudnode->dudnum; i++)
1305 {
1306 if (dudnode->files[i].size > 0)
1307 {
1308 dud_size += dudnode->files[i].size + sizeof(cpio_newc_header);
1309 }
1310 }
1311 }
1312 else
1313 {
1314 debug("dud not configed %s\n", args[1]);
1315 }
1316
1317 g_ventoy_cpio_buf = grub_malloc(file->size + archfile->size + 40960 + template_size +
1318 persistent_size + injection_size + dud_size + img_chunk_size);
1319 if (NULL == g_ventoy_cpio_buf)
1320 {
1321 grub_file_close(file);
1322 grub_file_close(archfile);
1323 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size);
1324 }
1325
1326 grub_file_read(file, g_ventoy_cpio_buf, file->size);
1327 buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4);
1328 while (*((grub_uint32_t *)buf) != 0x37303730)
1329 {
1330 buf -= 4;
1331 }
1332
1333 grub_file_read(archfile, buf, archfile->size);
1334 buf += (archfile->size - 4);
1335 while (*((grub_uint32_t *)buf) != 0x37303730)
1336 {
1337 buf -= 4;
1338 }
1339
1340 /* get initrd head len */
1341 initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx");
1342
1343 /* step1: insert image chunk data to cpio */
1344 headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map");
1345 buf += headlen + ventoy_align(img_chunk_size, 4);
1346
1347 if (template_buf)
1348 {
1349 headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall");
1350 buf += headlen + ventoy_align(template_size, 4);
1351 }
1352
1353 if (persistent_size > 0 && persistent_buf)
1354 {
1355 headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
1356 buf += headlen + ventoy_align(persistent_size, 4);
1357
1358 grub_free(persistent_buf);
1359 persistent_buf = NULL;
1360 }
1361
1362 if (injection_size > 0 && injection_buf)
1363 {
1364 headlen = ventoy_cpio_newc_fill_head(buf, injection_size, injection_buf, "ventoy/ventoy_injection");
1365 buf += headlen + ventoy_align(injection_size, 4);
1366
1367 grub_free(injection_buf);
1368 injection_buf = NULL;
1369 }
1370
1371 if (dud_size > 0)
1372 {
1373 for (i = 0; i < dudnode->dudnum; i++)
1374 {
1375 pos = grub_strrchr(dudnode->dudpath[i].path, '.');
1376 grub_snprintf(tmpname, sizeof(tmpname), "ventoy/ventoy_dud%d%s", i, (pos ? pos : ".iso"));
1377 dud_size = dudnode->files[i].size;
1378 headlen = ventoy_cpio_newc_fill_head(buf, dud_size, dudnode->files[i].buf, tmpname);
1379 buf += headlen + ventoy_align(dud_size, 4);
1380 }
1381 }
1382
1383 /* step2: insert os param to cpio */
1384 headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
1385 padlen = sizeof(ventoy_os_param);
1386 g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len;
1387 mod = g_ventoy_cpio_size % 2048;
1388 if (mod)
1389 {
1390 g_ventoy_cpio_size += 2048 - mod;
1391 padlen += 2048 - mod;
1392 }
1393
1394 /* update os param data size, the data will be updated before chain boot */
1395 ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8);
1396 g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen;
1397
1398 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1399 g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen);
1400 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx");
1401
1402 grub_file_close(file);
1403 grub_file_close(archfile);
1404
1405 if (grub_strcmp(args[3], "busybox=64") == 0)
1406 {
1407 debug("cpio busybox proc %s\n", args[3]);
1408 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "64h");
1409 }
1410 else if (grub_strcmp(args[3], "busybox=a64") == 0)
1411 {
1412 debug("cpio busybox proc %s\n", args[3]);
1413 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "a64");
1414 }
1415 else if (grub_strcmp(args[3], "busybox=m64") == 0)
1416 {
1417 debug("cpio busybox proc %s\n", args[3]);
1418 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "m64");
1419 }
1420
1421 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1422 }
1423
1424 grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1425 {
1426 int mod;
1427 int bufsize;
1428 int namelen;
1429 int offset;
1430 char *name;
1431 grub_uint8_t *bufend;
1432 cpio_newc_header *head;
1433 grub_file_t file;
1434 char value[64];
1435 const grub_uint8_t trailler[124] = {
1436 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1437 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1438 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1439 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1440 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1441 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1442 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1443 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1444 };
1445
1446 (void)ctxt;
1447 (void)argc;
1448
1449 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], args[1]);
1450 if (!file)
1451 {
1452 return 1;
1453 }
1454
1455 grub_memset(g_ventoy_runtime_buf, 0, sizeof(ventoy_os_param));
1456 ventoy_fill_os_param(file, (ventoy_os_param *)g_ventoy_runtime_buf);
1457
1458 grub_file_close(file);
1459
1460 grub_memcpy(g_ventoy_initrd_head, trailler, sizeof(trailler));
1461 bufend = (grub_uint8_t *)g_ventoy_initrd_head + sizeof(trailler);
1462
1463 bufsize = (int)(bufend - g_ventoy_cpio_buf);
1464 mod = bufsize % 512;
1465 if (mod)
1466 {
1467 grub_memset(bufend, 0, 512 - mod);
1468 bufsize += 512 - mod;
1469 }
1470
1471 if (argc > 1 && grub_strcmp(args[2], "noinit") == 0)
1472 {
1473 head = (cpio_newc_header *)g_ventoy_cpio_buf;
1474 name = (char *)(head + 1);
1475
1476 while (grub_strcmp(name, "TRAILER!!!"))
1477 {
1478 if (grub_strcmp(name, "init") == 0)
1479 {
1480 grub_memcpy(name, "xxxx", 4);
1481 }
1482 else if (grub_strcmp(name, "linuxrc") == 0)
1483 {
1484 grub_memcpy(name, "vtoyxrc", 7);
1485 }
1486 else if (grub_strcmp(name, "sbin") == 0)
1487 {
1488 grub_memcpy(name, "vtoy", 4);
1489 }
1490 else if (grub_strcmp(name, "sbin/init") == 0)
1491 {
1492 grub_memcpy(name, "vtoy/vtoy", 9);
1493 }
1494
1495 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1496 offset = sizeof(cpio_newc_header) + namelen;
1497 offset = ventoy_align(offset, 4);
1498 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1499 offset = ventoy_align(offset, 4);
1500
1501 head = (cpio_newc_header *)((char *)head + offset);
1502 name = (char *)(head + 1);
1503 }
1504 }
1505
1506 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)g_ventoy_cpio_buf);
1507 ventoy_set_env("ventoy_cpio_addr", value);
1508 grub_snprintf(value, sizeof(value), "%d", bufsize);
1509 ventoy_set_env("ventoy_cpio_size", value);
1510
1511 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1512 }
1513
1514 grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1515 {
1516 int len = 0;
1517 int ventoy_compatible = 0;
1518 grub_uint32_t size = 0;
1519 grub_uint64_t isosize = 0;
1520 grub_uint32_t boot_catlog = 0;
1521 grub_uint32_t img_chunk_size = 0;
1522 grub_uint32_t override_count = 0;
1523 grub_uint32_t override_size = 0;
1524 grub_uint32_t virt_chunk_count = 0;
1525 grub_uint32_t virt_chunk_size = 0;
1526 grub_file_t file;
1527 grub_disk_t disk;
1528 const char *pLastChain = NULL;
1529 const char *compatible;
1530 ventoy_chain_head *chain;
1531 char envbuf[64];
1532
1533 (void)ctxt;
1534 (void)argc;
1535
1536 compatible = grub_env_get("ventoy_compatible");
1537 if (compatible && compatible[0] == 'Y')
1538 {
1539 ventoy_compatible = 1;
1540 }
1541
1542 if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL))
1543 {
1544 grub_printf("ventoy not ready\n");
1545 return 1;
1546 }
1547
1548 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1549 if (!file)
1550 {
1551 return 1;
1552 }
1553
1554 isosize = file->size;
1555
1556 len = (int)grub_strlen(args[0]);
1557 if (len >= 4 && 0 == grub_strcasecmp(args[0] + len - 4, ".img"))
1558 {
1559 debug("boot catlog %u for img file\n", boot_catlog);
1560 }
1561 else
1562 {
1563 boot_catlog = ventoy_get_iso_boot_catlog(file);
1564 if (boot_catlog)
1565 {
1566 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1567 {
1568 grub_env_set("LoadIsoEfiDriver", "on");
1569 }
1570 }
1571 else
1572 {
1573 if (ventoy_is_efi_os())
1574 {
1575 grub_env_set("LoadIsoEfiDriver", "on");
1576 }
1577 else
1578 {
1579 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1580 }
1581 }
1582 }
1583
1584 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1585
1586 override_count = ventoy_linux_get_override_chunk_count();
1587 virt_chunk_count = ventoy_linux_get_virt_chunk_count();
1588
1589 if (ventoy_compatible)
1590 {
1591 size = sizeof(ventoy_chain_head) + img_chunk_size;
1592 }
1593 else
1594 {
1595 override_size = ventoy_linux_get_override_chunk_size();
1596 virt_chunk_size = ventoy_linux_get_virt_chunk_size();
1597 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1598 }
1599
1600 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1601 if (pLastChain)
1602 {
1603 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1604 if (chain)
1605 {
1606 debug("free last chain memory %p\n", chain);
1607 grub_free(chain);
1608 }
1609 }
1610
1611 chain = grub_malloc(size);
1612 if (!chain)
1613 {
1614 grub_printf("Failed to alloc chain memory size %u\n", size);
1615 grub_file_close(file);
1616 return 1;
1617 }
1618
1619 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1620 grub_env_set("vtoy_chain_mem_addr", envbuf);
1621 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1622 grub_env_set("vtoy_chain_mem_size", envbuf);
1623
1624 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1625
1626 /* part 1: os parameter */
1627 g_ventoy_chain_type = ventoy_chain_linux;
1628 ventoy_fill_os_param(file, &(chain->os_param));
1629
1630 /* part 2: chain head */
1631 disk = file->device->disk;
1632 chain->disk_drive = disk->id;
1633 chain->disk_sector_size = (1 << disk->log_sector_size);
1634 chain->real_img_size_in_bytes = file->size;
1635 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1636 chain->boot_catalog = boot_catlog;
1637
1638 if (!ventoy_is_efi_os())
1639 {
1640 grub_file_seek(file, boot_catlog * 2048);
1641 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1642 }
1643
1644 /* part 3: image chunk */
1645 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1646 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1647 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1648
1649 if (ventoy_compatible)
1650 {
1651 return 0;
1652 }
1653
1654 /* part 4: override chunk */
1655 if (override_count > 0)
1656 {
1657 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1658 chain->override_chunk_num = override_count;
1659 ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
1660 }
1661
1662 /* part 5: virt chunk */
1663 if (virt_chunk_count > 0)
1664 {
1665 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1666 chain->virt_chunk_num = virt_chunk_count;
1667 ventoy_linux_fill_virt_data(isosize, chain);
1668 }
1669
1670 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1671 }
1672