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