]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
c3548e84d81185cae610cc63b21c3afd4399b640
[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 VTOY_SKIP_SPACE(start);
181
182 offset = 7; // strlen("initrd=") or "INITRD " or "initrd "
183 pos = grub_strstr(start, "initrd=");
184 if (pos == NULL)
185 {
186 pos = start;
187
188 if (grub_strncmp(start, "INITRD", 6) != 0 && grub_strncmp(start, "initrd", 6) != 0)
189 {
190 if (grub_strstr(start, "xen") &&
191 ((pos = grub_strstr(start, "--- /install.img")) != NULL ||
192 (pos = grub_strstr(start, "--- initrd.img")) != NULL
193 ))
194 {
195 offset = 4; // "--- "
196 }
197 else
198 {
199 continue;
200 }
201 }
202 }
203
204 pos += offset;
205
206 while (1)
207 {
208 i = 0;
209 img = grub_zalloc(sizeof(initrd_info));
210 if (!img)
211 {
212 break;
213 }
214
215 if (*pos != '/')
216 {
217 grub_strcpy(img->name, prefix);
218 i = prefixlen;
219 }
220
221 while (i < 255 && (0 == ventoy_is_word_end(*pos)))
222 {
223 img->name[i++] = *pos++;
224 }
225
226 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
227 {
228 grub_free(img);
229 }
230 else
231 {
232 if (g_initrd_img_list)
233 {
234 img->prev = g_initrd_img_tail;
235 g_initrd_img_tail->next = img;
236 }
237 else
238 {
239 g_initrd_img_list = img;
240 }
241
242 g_initrd_img_tail = img;
243 g_initrd_img_count++;
244 }
245
246 if (*pos == ',')
247 {
248 pos++;
249 }
250 else
251 {
252 break;
253 }
254 }
255 }
256
257 grub_free(buf);
258 return GRUB_ERR_NONE;
259 }
260
261 static int ventoy_isolinux_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
262 {
263 grub_file_t file = NULL;
264 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
265
266 (void)info;
267
268 if (NULL == grub_strstr(filename, ".cfg") && NULL == grub_strstr(filename, ".CFG"))
269 {
270 return 0;
271 }
272
273 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
274
275 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ctx->path_prefix, filename);
276 if (!file)
277 {
278 return 0;
279 }
280
281 ventoy_isolinux_initrd_collect(file, ctx->dir_prefix);
282 grub_file_close(file);
283
284 return 0;
285 }
286
287 grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
288 {
289 grub_fs_t fs;
290 grub_device_t dev = NULL;
291 char *device_name = NULL;
292 ventoy_initrd_ctx ctx;
293 char directory[256];
294
295 (void)ctxt;
296 (void)argc;
297
298 device_name = grub_file_get_device_name(args[0]);
299 if (!device_name)
300 {
301 goto end;
302 }
303
304 dev = grub_device_open(device_name);
305 if (!dev)
306 {
307 goto end;
308 }
309
310 fs = grub_fs_probe(dev);
311 if (!fs)
312 {
313 goto end;
314 }
315
316 debug("isolinux initrd collect %s\n", args[0]);
317
318 ventoy_parse_directory(args[0], directory, sizeof(directory) - 1);
319 ctx.path_prefix = args[0];
320 ctx.dir_prefix = (argc > 1) ? args[1] : directory;
321
322 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx.path_prefix, ctx.dir_prefix);
323
324 fs->fs_dir(dev, directory, ventoy_isolinux_initrd_hook, &ctx);
325
326 end:
327 check_free(device_name, grub_free);
328 check_free(dev, grub_device_close);
329
330 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
331 }
332
333 static int ventoy_linux_initrd_collect_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
334 {
335 int len;
336 initrd_info *img = NULL;
337
338 (void)data;
339
340 if (0 == info->dir)
341 {
342 if (grub_strncmp(filename, "initrd", 6) == 0)
343 {
344 len = (int)grub_strlen(filename);
345 if (grub_strcmp(filename + len - 4, ".img") == 0)
346 {
347 img = grub_zalloc(sizeof(initrd_info));
348 if (img)
349 {
350 grub_snprintf(img->name, sizeof(img->name), "/boot/%s", filename);
351
352 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
353 {
354 grub_free(img);
355 }
356 else
357 {
358 if (g_initrd_img_list)
359 {
360 img->prev = g_initrd_img_tail;
361 g_initrd_img_tail->next = img;
362 }
363 else
364 {
365 g_initrd_img_list = img;
366 }
367
368 g_initrd_img_tail = img;
369 g_initrd_img_count++;
370 }
371 }
372 }
373 }
374 }
375
376 return 0;
377 }
378
379 static int ventoy_linux_collect_boot_initrds(void)
380 {
381 grub_fs_t fs;
382 grub_device_t dev = NULL;
383
384 dev = grub_device_open("loop");
385 if (!dev)
386 {
387 debug("failed to open device loop\n");
388 goto end;
389 }
390
391 fs = grub_fs_probe(dev);
392 if (!fs)
393 {
394 debug("failed to probe fs %d\n", grub_errno);
395 goto end;
396 }
397
398 fs->fs_dir(dev, "/boot", ventoy_linux_initrd_collect_hook, NULL);
399
400 end:
401 return 0;
402 }
403
404 static grub_err_t ventoy_grub_cfg_initrd_collect(const char *fileName)
405 {
406 int i = 0;
407 int len = 0;
408 int dollar = 0;
409 int quotation = 0;
410 int initrd_dollar = 0;
411 grub_file_t file = NULL;
412 char *buf = NULL;
413 char *start = NULL;
414 char *nextline = NULL;
415 initrd_info *img = NULL;
416
417 debug("grub initrd collect %s\n", fileName);
418
419 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", fileName);
420 if (!file)
421 {
422 return 0;
423 }
424
425 buf = grub_zalloc(file->size + 2);
426 if (!buf)
427 {
428 grub_file_close(file);
429 return 0;
430 }
431
432 grub_file_read(file, buf, file->size);
433
434 for (start = buf; start; start = nextline)
435 {
436 nextline = ventoy_get_line(start);
437
438 VTOY_SKIP_SPACE(start);
439
440 if (grub_strncmp(start, "initrd", 6) != 0)
441 {
442 continue;
443 }
444
445 start += 6;
446 while (*start && (!ventoy_isspace(*start)))
447 {
448 start++;
449 }
450
451 VTOY_SKIP_SPACE(start);
452
453 if (*start == '"')
454 {
455 quotation = 1;
456 start++;
457 }
458
459 while (*start)
460 {
461 img = grub_zalloc(sizeof(initrd_info));
462 if (!img)
463 {
464 break;
465 }
466
467 dollar = 0;
468 for (i = 0; i < 255 && (0 == ventoy_is_word_end(*start)); i++)
469 {
470 img->name[i] = *start++;
471 if (img->name[i] == '$')
472 {
473 dollar = 1;
474 }
475 }
476
477 if (quotation)
478 {
479 len = (int)grub_strlen(img->name);
480 if (len > 2 && img->name[len - 1] == '"')
481 {
482 img->name[len - 1] = 0;
483 }
484 debug("Remove quotation <%s>\n", img->name);
485 }
486
487 /* special process for /boot/initrd$XXX.img */
488 if (dollar == 1)
489 {
490 if (grub_strncmp(img->name, "/boot/initrd$", 13) == 0)
491 {
492 len = (int)grub_strlen(img->name);
493 if (grub_strcmp(img->name + len - 4, ".img") == 0)
494 {
495 initrd_dollar++;
496 }
497 }
498 }
499
500 if (dollar == 1 || ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
501 {
502 grub_free(img);
503 }
504 else
505 {
506 if (g_initrd_img_list)
507 {
508 img->prev = g_initrd_img_tail;
509 g_initrd_img_tail->next = img;
510 }
511 else
512 {
513 g_initrd_img_list = img;
514 }
515
516 g_initrd_img_tail = img;
517 g_initrd_img_count++;
518 }
519
520 if (*start == ' ' || *start == '\t')
521 {
522 VTOY_SKIP_SPACE(start);
523 }
524 else
525 {
526 break;
527 }
528 }
529 }
530
531 grub_free(buf);
532 grub_file_close(file);
533
534 if (initrd_dollar > 0 && grub_strncmp(fileName, "(loop)/", 7) == 0)
535 {
536 debug("collect initrd variable %d\n", initrd_dollar);
537 ventoy_linux_collect_boot_initrds();
538 }
539
540 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
541 }
542
543 static int ventoy_grub_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
544 {
545 char filePath[256];
546 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
547
548 (void)info;
549
550 debug("ventoy_grub_initrd_hook %s\n", filename);
551
552 if (NULL == grub_strstr(filename, ".cfg") &&
553 NULL == grub_strstr(filename, ".CFG") &&
554 NULL == grub_strstr(filename, ".conf"))
555 {
556 return 0;
557 }
558
559 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
560
561 grub_snprintf(filePath, sizeof(filePath) - 1, "%s%s", ctx->dir_prefix, filename);
562 ventoy_grub_cfg_initrd_collect(filePath);
563
564 return 0;
565 }
566
567 grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
568 {
569 grub_fs_t fs;
570 grub_device_t dev = NULL;
571 char *device_name = NULL;
572 ventoy_initrd_ctx ctx;
573
574 (void)ctxt;
575 (void)argc;
576
577 if (argc != 2)
578 {
579 return 0;
580 }
581
582 debug("grub initrd collect %s %s\n", args[0], args[1]);
583
584 if (grub_strcmp(args[0], "file") == 0)
585 {
586 return ventoy_grub_cfg_initrd_collect(args[1]);
587 }
588
589 device_name = grub_file_get_device_name(args[1]);
590 if (!device_name)
591 {
592 debug("failed to get device name %s\n", args[1]);
593 goto end;
594 }
595
596 dev = grub_device_open(device_name);
597 if (!dev)
598 {
599 debug("failed to open device %s\n", device_name);
600 goto end;
601 }
602
603 fs = grub_fs_probe(dev);
604 if (!fs)
605 {
606 debug("failed to probe fs %d\n", grub_errno);
607 goto end;
608 }
609
610 ctx.dir_prefix = args[1];
611 ctx.path_prefix = grub_strstr(args[1], device_name);
612 if (ctx.path_prefix)
613 {
614 ctx.path_prefix += grub_strlen(device_name) + 1;
615 }
616 else
617 {
618 ctx.path_prefix = args[1];
619 }
620
621 debug("ctx.path_prefix:<%s>\n", ctx.path_prefix);
622
623 fs->fs_dir(dev, ctx.path_prefix, ventoy_grub_initrd_hook, &ctx);
624
625 end:
626 check_free(device_name, grub_free);
627 check_free(dev, grub_device_close);
628
629
630 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
631 }
632
633 grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args)
634 {
635 initrd_info *img = NULL;
636
637 (void)ctxt;
638 (void)argc;
639
640 debug("ventoy_cmd_specify_initrd_file %s\n", args[0]);
641
642 img = grub_zalloc(sizeof(initrd_info));
643 if (!img)
644 {
645 return 1;
646 }
647
648 grub_strncpy(img->name, args[0], sizeof(img->name));
649 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
650 {
651 debug("%s is already exist\n", args[0]);
652 grub_free(img);
653 }
654 else
655 {
656 if (g_initrd_img_list)
657 {
658 img->prev = g_initrd_img_tail;
659 g_initrd_img_tail->next = img;
660 }
661 else
662 {
663 g_initrd_img_list = img;
664 }
665
666 g_initrd_img_tail = img;
667 g_initrd_img_count++;
668 }
669
670 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
671 }
672
673 static int ventoy_cpio_newc_get_int(char *value)
674 {
675 char buf[16] = {0};
676
677 grub_memcpy(buf, value, 8);
678 return (int)grub_strtoul(buf, NULL, 16);
679 }
680
681 static void ventoy_cpio_newc_fill_int(grub_uint32_t value, char *buf, int buflen)
682 {
683 int i;
684 int len;
685 char intbuf[32];
686
687 len = grub_snprintf(intbuf, sizeof(intbuf), "%x", value);
688
689 for (i = 0; i < buflen; i++)
690 {
691 buf[i] = '0';
692 }
693
694 if (len > buflen)
695 {
696 grub_printf("int buf len overflow %d %d\n", len, buflen);
697 }
698 else
699 {
700 grub_memcpy(buf + buflen - len, intbuf, len);
701 }
702 }
703
704 int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name)
705 {
706 int namelen = 0;
707 int headlen = 0;
708 static grub_uint32_t cpio_ino = 0xFFFFFFF0;
709 cpio_newc_header *cpio = (cpio_newc_header *)buf;
710
711 namelen = grub_strlen(name) + 1;
712 headlen = sizeof(cpio_newc_header) + namelen;
713 headlen = ventoy_align(headlen, 4);
714
715 grub_memset(cpio, '0', sizeof(cpio_newc_header));
716 grub_memset(cpio + 1, 0, headlen - sizeof(cpio_newc_header));
717
718 grub_memcpy(cpio->c_magic, "070701", 6);
719 ventoy_cpio_newc_fill_int(cpio_ino--, cpio->c_ino, 8);
720 ventoy_cpio_newc_fill_int(0100777, cpio->c_mode, 8);
721 ventoy_cpio_newc_fill_int(1, cpio->c_nlink, 8);
722 ventoy_cpio_newc_fill_int(filesize, cpio->c_filesize, 8);
723 ventoy_cpio_newc_fill_int(namelen, cpio->c_namesize, 8);
724 grub_memcpy(cpio + 1, name, namelen);
725
726 if (filedata)
727 {
728 grub_memcpy((char *)cpio + headlen, filedata, filesize);
729 }
730
731 return headlen;
732 }
733
734 static grub_uint32_t ventoy_linux_get_virt_chunk_count(void)
735 {
736 int i;
737 grub_uint32_t count = g_valid_initrd_count;
738
739 if (g_conf_replace_count > 0)
740 {
741 for (i = 0; i < g_conf_replace_count; i++)
742 {
743 if (g_conf_replace_offset[i] > 0)
744 {
745 count++;
746 }
747 }
748 }
749
750 if (g_append_ext_sector > 0)
751 {
752 count++;
753 }
754
755 return count;
756 }
757
758 static grub_uint32_t ventoy_linux_get_virt_chunk_size(void)
759 {
760 int i;
761 grub_uint32_t size;
762
763 size = (sizeof(ventoy_virt_chunk) + g_ventoy_cpio_size) * g_valid_initrd_count;
764
765 if (g_conf_replace_count > 0)
766 {
767 for (i = 0; i < g_conf_replace_count; i++)
768 {
769 if (g_conf_replace_offset[i] > 0)
770 {
771 size += sizeof(ventoy_virt_chunk) + g_conf_replace_new_len_align[i];
772 }
773 }
774 }
775
776 if (g_append_ext_sector > 0)
777 {
778 size += sizeof(ventoy_virt_chunk) + VTOY_APPEND_EXT_SIZE;
779 }
780
781 return size;
782 }
783
784 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
785 {
786 int i = 0;
787 int id = 0;
788 int virtid = 0;
789 initrd_info *node;
790 grub_uint64_t sector;
791 grub_uint32_t offset;
792 grub_uint32_t cpio_secs;
793 grub_uint32_t initrd_secs;
794 char *override;
795 ventoy_virt_chunk *cur;
796 ventoy_grub_param_file_replace *replace = NULL;
797 char name[32];
798
799 override = (char *)chain + chain->virt_chunk_offset;
800 sector = (isosize + 2047) / 2048;
801 cpio_secs = g_ventoy_cpio_size / 2048;
802
803 offset = ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk);
804 cur = (ventoy_virt_chunk *)override;
805
806 for (node = g_initrd_img_list; node; node = node->next)
807 {
808 if (node->size == 0)
809 {
810 continue;
811 }
812
813 initrd_secs = (grub_uint32_t)((node->size + 2047) / 2048);
814
815 cur->mem_sector_start = sector;
816 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
817 cur->mem_sector_offset = offset;
818 cur->remap_sector_start = cur->mem_sector_end;
819 cur->remap_sector_end = cur->remap_sector_start + initrd_secs;
820 cur->org_sector_start = (grub_uint32_t)(node->offset / 2048);
821
822 grub_memcpy(g_ventoy_runtime_buf, &chain->os_param, sizeof(ventoy_os_param));
823
824 grub_memset(name, 0, 16);
825 grub_snprintf(name, sizeof(name), "initrd%03d", ++id);
826
827 grub_memcpy(g_ventoy_initrd_head + 1, name, 16);
828 ventoy_cpio_newc_fill_int((grub_uint32_t)node->size, g_ventoy_initrd_head->c_filesize, 8);
829
830 grub_memcpy(override + offset, g_ventoy_cpio_buf, g_ventoy_cpio_size);
831
832 chain->virt_img_size_in_bytes += g_ventoy_cpio_size + initrd_secs * 2048;
833
834 offset += g_ventoy_cpio_size;
835 sector += cpio_secs + initrd_secs;
836 cur++;
837 virtid++;
838 }
839
840 /* Lenovo EasyStartup need an addional sector for boundary check */
841 if (g_append_ext_sector > 0)
842 {
843 cpio_secs = VTOY_APPEND_EXT_SIZE / 2048;
844
845 cur->mem_sector_start = sector;
846 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
847 cur->mem_sector_offset = offset;
848 cur->remap_sector_start = 0;
849 cur->remap_sector_end = 0;
850 cur->org_sector_start = 0;
851
852 grub_memset(override + offset, 0, VTOY_APPEND_EXT_SIZE);
853
854 chain->virt_img_size_in_bytes += VTOY_APPEND_EXT_SIZE;
855
856 offset += VTOY_APPEND_EXT_SIZE;
857 sector += cpio_secs;
858 cur++;
859 virtid++;
860 }
861
862 if (g_conf_replace_count > 0)
863 {
864 for (i = 0; i < g_conf_replace_count; i++)
865 {
866 if (g_conf_replace_offset[i] > 0)
867 {
868 cpio_secs = g_conf_replace_new_len_align[i] / 2048;
869
870 cur->mem_sector_start = sector;
871 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
872 cur->mem_sector_offset = offset;
873 cur->remap_sector_start = 0;
874 cur->remap_sector_end = 0;
875 cur->org_sector_start = 0;
876
877 grub_memcpy(override + offset, g_conf_replace_new_buf[i], g_conf_replace_new_len[i]);
878
879 chain->virt_img_size_in_bytes += g_conf_replace_new_len_align[i];
880
881 replace = g_grub_param->img_replace + i;
882 if (replace->magic == GRUB_IMG_REPLACE_MAGIC)
883 {
884 replace->new_file_virtual_id = virtid;
885 }
886
887 offset += g_conf_replace_new_len_align[i];
888 sector += cpio_secs;
889 cur++;
890 virtid++;
891 }
892 }
893 }
894
895 return;
896 }
897
898 static grub_uint32_t ventoy_linux_get_override_chunk_count(void)
899 {
900 int i;
901 grub_uint32_t count = g_valid_initrd_count;
902
903 if (g_conf_replace_count > 0)
904 {
905 for (i = 0; i < g_conf_replace_count; i++)
906 {
907 if (g_conf_replace_offset[i] > 0)
908 {
909 count++;
910 }
911 }
912 }
913
914 if (g_svd_replace_offset > 0)
915 {
916 count++;
917 }
918
919 return count;
920 }
921
922 static grub_uint32_t ventoy_linux_get_override_chunk_size(void)
923 {
924 int i;
925 int count = g_valid_initrd_count;
926
927 if (g_conf_replace_count > 0)
928 {
929 for (i = 0; i < g_conf_replace_count; i++)
930 {
931 if (g_conf_replace_offset[i] > 0)
932 {
933 count++;
934 }
935 }
936 }
937
938 if (g_svd_replace_offset > 0)
939 {
940 count++;
941 }
942
943 return sizeof(ventoy_override_chunk) * count;
944 }
945
946 static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override)
947 {
948 int i;
949 initrd_info *node;
950 grub_uint32_t mod;
951 grub_uint32_t newlen;
952 grub_uint64_t sector;
953 ventoy_override_chunk *cur;
954 ventoy_iso9660_override *dirent;
955 ventoy_udf_override *udf;
956
957 sector = (isosize + 2047) / 2048;
958
959 cur = (ventoy_override_chunk *)override;
960 for (node = g_initrd_img_list; node; node = node->next)
961 {
962 if (node->size == 0)
963 {
964 continue;
965 }
966
967 newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
968 mod = newlen % 4;
969 if (mod > 0)
970 {
971 newlen += 4 - mod; /* cpio must align with 4 */
972 }
973
974 if (node->iso_type == 0)
975 {
976 dirent = (ventoy_iso9660_override *)node->override_data;
977
978 node->override_length = sizeof(ventoy_iso9660_override);
979 dirent->first_sector = (grub_uint32_t)sector;
980 dirent->size = newlen;
981 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
982 dirent->size_be = grub_swap_bytes32(dirent->size);
983
984 sector += (dirent->size + 2047) / 2048;
985 }
986 else
987 {
988 udf = (ventoy_udf_override *)node->override_data;
989
990 node->override_length = sizeof(ventoy_udf_override);
991 udf->length = newlen;
992 udf->position = (grub_uint32_t)sector - node->udf_start_block;
993
994 sector += (udf->length + 2047) / 2048;
995 }
996
997 cur->img_offset = node->override_offset;
998 cur->override_size = node->override_length;
999 grub_memcpy(cur->override_data, node->override_data, cur->override_size);
1000 cur++;
1001 }
1002
1003 if (g_conf_replace_count > 0)
1004 {
1005 for (i = 0; i < g_conf_replace_count; i++)
1006 {
1007 if (g_conf_replace_offset[i] > 0)
1008 {
1009 cur->img_offset = g_conf_replace_offset[i];
1010 cur->override_size = sizeof(ventoy_iso9660_override);
1011
1012 newlen = (grub_uint32_t)(g_conf_replace_new_len[i]);
1013
1014 dirent = (ventoy_iso9660_override *)cur->override_data;
1015 dirent->first_sector = (grub_uint32_t)sector;
1016 dirent->size = newlen;
1017 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
1018 dirent->size_be = grub_swap_bytes32(dirent->size);
1019
1020 sector += (dirent->size + 2047) / 2048;
1021 cur++;
1022 }
1023 }
1024 }
1025
1026 if (g_svd_replace_offset > 0)
1027 {
1028 cur->img_offset = g_svd_replace_offset;
1029 cur->override_size = 1;
1030 cur->override_data[0] = 0xFF;
1031 cur++;
1032 }
1033
1034 return;
1035 }
1036
1037 grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
1038 {
1039 char buf[32] = {0};
1040
1041 (void)ctxt;
1042 (void)argc;
1043 (void)args;
1044
1045 if (argc == 1)
1046 {
1047 grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count);
1048 grub_env_set(args[0], buf);
1049 }
1050
1051 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1052 }
1053
1054 grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
1055 {
1056 char buf[32] = {0};
1057
1058 (void)ctxt;
1059 (void)argc;
1060 (void)args;
1061
1062 if (argc == 1)
1063 {
1064 grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count);
1065 grub_env_set(args[0], buf);
1066 }
1067
1068 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1069 }
1070
1071 static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt)
1072 {
1073 int data;
1074 int filtbysize = 1;
1075 int sizefilt = 0;
1076 grub_file_t file;
1077 initrd_info *node;
1078
1079 debug("ventoy_linux_locate_initrd %d\n", filt);
1080
1081 g_valid_initrd_count = 0;
1082
1083 if (grub_env_get("INITRD_NO_SIZE_FILT"))
1084 {
1085 filtbysize = 0;
1086 }
1087
1088 for (node = g_initrd_img_list; node; node = node->next)
1089 {
1090 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name);
1091 if (!file)
1092 {
1093 continue;
1094 }
1095
1096 debug("file <%s> size:%d\n", node->name, (int)file->size);
1097
1098 /* initrd file too small */
1099 if (filtbysize
1100 && (NULL == grub_strstr(node->name, "minirt.gz"))
1101 && (NULL == grub_strstr(node->name, "initrd.xz"))
1102 )
1103 {
1104 if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048)
1105 {
1106 debug("file size too small %d\n", (int)g_ventoy_cpio_size);
1107 grub_file_close(file);
1108 sizefilt++;
1109 continue;
1110 }
1111 }
1112
1113 /* skip hdt.img */
1114 if (file->size <= VTOY_SIZE_1MB && grub_strcmp(node->name, "/boot/hdt.img") == 0)
1115 {
1116 continue;
1117 }
1118
1119 if (grub_strcmp(file->fs->name, "iso9660") == 0)
1120 {
1121 node->iso_type = 0;
1122 node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
1123
1124 grub_file_read(file, &data, 1); // just read for hook trigger
1125 node->offset = grub_iso9660_get_last_read_pos(file);
1126 }
1127 else
1128 {
1129 /* TBD */
1130 }
1131
1132 node->size = file->size;
1133 g_valid_initrd_count++;
1134
1135 grub_file_close(file);
1136 }
1137
1138 *filtcnt = sizefilt;
1139
1140 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1141 }
1142
1143
1144 grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args)
1145 {
1146 int index = 0;
1147 char buf[32];
1148 initrd_info *node = NULL;
1149
1150 (void)ctxt;
1151 (void)argc;
1152 (void)args;
1153
1154 if (argc != 1)
1155 {
1156 return 1;
1157 }
1158
1159 if (g_initrd_img_count == 1)
1160 {
1161 ventoy_set_env(args[0], "0");
1162 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1163 }
1164
1165 for (node = g_initrd_img_list; node; node = node->next)
1166 {
1167 if (node->size <= 0)
1168 {
1169 continue;
1170 }
1171
1172 if (grub_strstr(node->name, "ucode") || grub_strstr(node->name, "-firmware"))
1173 {
1174 index++;
1175 continue;
1176 }
1177
1178 grub_snprintf(buf, sizeof(buf), "%d", index);
1179 ventoy_set_env(args[0], buf);
1180 break;
1181 }
1182
1183 debug("main initrd index:%d\n", index);
1184
1185 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1186 }
1187
1188 grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
1189 {
1190 int sizefilt = 0;
1191
1192 (void)ctxt;
1193 (void)argc;
1194 (void)args;
1195
1196 ventoy_linux_locate_initrd(1, &sizefilt);
1197
1198 if (g_valid_initrd_count == 0 && sizefilt > 0)
1199 {
1200 ventoy_linux_locate_initrd(0, &sizefilt);
1201 }
1202
1203 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1204 }
1205
1206 static int ventoy_cpio_busybox64(cpio_newc_header *head, const char *file)
1207 {
1208 char *name;
1209 int namelen;
1210 int offset;
1211 int count = 0;
1212 char filepath[128];
1213
1214 grub_snprintf(filepath, sizeof(filepath), "ventoy/busybox/%s", file);
1215
1216 name = (char *)(head + 1);
1217 while (name[0] && count < 2)
1218 {
1219 if (grub_strcmp(name, "ventoy/busybox/ash") == 0)
1220 {
1221 grub_memcpy(name, "ventoy/busybox/32h", 18);
1222 count++;
1223 }
1224 else if (grub_strcmp(name, filepath) == 0)
1225 {
1226 grub_memcpy(name, "ventoy/busybox/ash", 18);
1227 count++;
1228 }
1229
1230 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1231 offset = sizeof(cpio_newc_header) + namelen;
1232 offset = ventoy_align(offset, 4);
1233 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1234 offset = ventoy_align(offset, 4);
1235
1236 head = (cpio_newc_header *)((char *)head + offset);
1237 name = (char *)(head + 1);
1238 }
1239
1240 return 0;
1241 }
1242
1243
1244 grub_err_t ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt, int argc, char **args)
1245 {
1246 (void)ctxt;
1247 (void)argc;
1248 (void)args;
1249
1250 debug("ventoy_cmd_busybox_64 %d\n", argc);
1251 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, args[0]);
1252 return 0;
1253 }
1254
1255 grub_err_t ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt, int argc, char **args)
1256 {
1257 int i;
1258 grub_file_t file;
1259 char buf[16];
1260
1261 (void)ctxt;
1262 (void)argc;
1263
1264 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1265 if (!file)
1266 {
1267 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1268 }
1269
1270 for (i = 0; i < 10; i++)
1271 {
1272 buf[0] = 0;
1273 grub_file_seek(file, (17 + i) * 2048);
1274 grub_file_read(file, buf, 16);
1275
1276 if (buf[0] == 2 && grub_strncmp(buf + 1, "CD001", 5) == 0)
1277 {
1278 debug("Find SVD at VD %d\n", i);
1279 g_svd_replace_offset = (17 + i) * 2048;
1280 break;
1281 }
1282 }
1283
1284 if (i >= 10)
1285 {
1286 debug("SVD not found %d\n", (int)g_svd_replace_offset);
1287 }
1288
1289 grub_file_close(file);
1290
1291 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1292 }
1293
1294 grub_err_t ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1295 {
1296 (void)ctxt;
1297 (void)argc;
1298 (void)args;
1299
1300 if (args[0][0] == '1')
1301 {
1302 g_append_ext_sector = 1;
1303 }
1304 else
1305 {
1306 g_append_ext_sector = 0;
1307 }
1308
1309 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1310 }
1311
1312 grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1313 {
1314 int i;
1315 int rc;
1316 char *pos = NULL;
1317 char *template_file = NULL;
1318 char *template_buf = NULL;
1319 char *persistent_buf = NULL;
1320 char *injection_buf = NULL;
1321 dud *dudnode = NULL;
1322 char tmpname[128];
1323 const char *injection_file = NULL;
1324 grub_uint8_t *buf = NULL;
1325 grub_uint32_t mod;
1326 grub_uint32_t headlen;
1327 grub_uint32_t initrd_head_len;
1328 grub_uint32_t padlen;
1329 grub_uint32_t img_chunk_size;
1330 grub_uint32_t template_size = 0;
1331 grub_uint32_t persistent_size = 0;
1332 grub_uint32_t injection_size = 0;
1333 grub_uint32_t dud_size = 0;
1334 grub_file_t file;
1335 grub_file_t archfile;
1336 grub_file_t tmpfile;
1337 install_template *template_node = NULL;
1338 ventoy_img_chunk_list chunk_list;
1339
1340 (void)ctxt;
1341 (void)argc;
1342
1343 if (argc != 4)
1344 {
1345 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name);
1346 }
1347
1348 if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0)
1349 {
1350 return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n");
1351 }
1352
1353 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1354
1355 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_COMM_CPIO);
1356 if (!file)
1357 {
1358 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_COMM_CPIO);
1359 }
1360
1361 archfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_ARCH_CPIO);
1362 if (!archfile)
1363 {
1364 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_ARCH_CPIO);
1365 grub_file_close(file);
1366 }
1367
1368 debug("load %s %s success\n", VTOY_COMM_CPIO, VTOY_ARCH_CPIO);
1369
1370 if (g_ventoy_cpio_buf)
1371 {
1372 grub_free(g_ventoy_cpio_buf);
1373 g_ventoy_cpio_buf = NULL;
1374 g_ventoy_cpio_size = 0;
1375 }
1376
1377 rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list);
1378 if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
1379 {
1380 persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1381 persistent_buf = (char *)(chunk_list.chunk);
1382 }
1383
1384 template_file = ventoy_plugin_get_cur_install_template(args[1], &template_node);
1385 if (template_file)
1386 {
1387 debug("auto install template: <%s> <addr:%p> <len:%d>\n",
1388 template_file, template_node->filebuf, template_node->filelen);
1389
1390 template_size = template_node->filelen;
1391 template_buf = grub_malloc(template_size);
1392 if (template_buf)
1393 {
1394 grub_memcpy(template_buf, template_node->filebuf, template_size);
1395 }
1396 }
1397 else
1398 {
1399 debug("auto install script skipped or not configed %s\n", args[1]);
1400 }
1401
1402 injection_file = ventoy_plugin_get_injection(args[1]);
1403 if (injection_file)
1404 {
1405 debug("injection archive: <%s>\n", injection_file);
1406 tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], injection_file);
1407 if (tmpfile)
1408 {
1409 debug("injection archive size:%d\n", (int)tmpfile->size);
1410 injection_size = tmpfile->size;
1411 injection_buf = grub_malloc(injection_size);
1412 if (injection_buf)
1413 {
1414 grub_file_read(tmpfile, injection_buf, injection_size);
1415 }
1416
1417 grub_file_close(tmpfile);
1418 }
1419 else
1420 {
1421 debug("Failed to open injection archive %s%s\n", args[2], injection_file);
1422 }
1423 }
1424 else
1425 {
1426 debug("injection not configed %s\n", args[1]);
1427 }
1428
1429 dudnode = ventoy_plugin_find_dud(args[1]);
1430 if (dudnode)
1431 {
1432 debug("dud file: <%d>\n", dudnode->dudnum);
1433 ventoy_plugin_load_dud(dudnode, args[2]);
1434 for (i = 0; i < dudnode->dudnum; i++)
1435 {
1436 if (dudnode->files[i].size > 0)
1437 {
1438 dud_size += dudnode->files[i].size + sizeof(cpio_newc_header);
1439 }
1440 }
1441 }
1442 else
1443 {
1444 debug("dud not configed %s\n", args[1]);
1445 }
1446
1447 g_ventoy_cpio_buf = grub_malloc(file->size + archfile->size + 40960 + template_size +
1448 persistent_size + injection_size + dud_size + img_chunk_size);
1449 if (NULL == g_ventoy_cpio_buf)
1450 {
1451 grub_file_close(file);
1452 grub_file_close(archfile);
1453 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size);
1454 }
1455
1456 grub_file_read(file, g_ventoy_cpio_buf, file->size);
1457 buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4);
1458 while (*((grub_uint32_t *)buf) != 0x37303730)
1459 {
1460 buf -= 4;
1461 }
1462
1463 grub_file_read(archfile, buf, archfile->size);
1464 buf += (archfile->size - 4);
1465 while (*((grub_uint32_t *)buf) != 0x37303730)
1466 {
1467 buf -= 4;
1468 }
1469
1470 /* get initrd head len */
1471 initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx");
1472
1473 /* step1: insert image chunk data to cpio */
1474 headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map");
1475 buf += headlen + ventoy_align(img_chunk_size, 4);
1476
1477 if (template_buf)
1478 {
1479 headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall");
1480 buf += headlen + ventoy_align(template_size, 4);
1481 grub_check_free(template_buf);
1482 }
1483
1484 if (persistent_size > 0 && persistent_buf)
1485 {
1486 headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
1487 buf += headlen + ventoy_align(persistent_size, 4);
1488 grub_check_free(persistent_buf);
1489 }
1490
1491 if (injection_size > 0 && injection_buf)
1492 {
1493 headlen = ventoy_cpio_newc_fill_head(buf, injection_size, injection_buf, "ventoy/ventoy_injection");
1494 buf += headlen + ventoy_align(injection_size, 4);
1495
1496 grub_free(injection_buf);
1497 injection_buf = NULL;
1498 }
1499
1500 if (dud_size > 0)
1501 {
1502 for (i = 0; i < dudnode->dudnum; i++)
1503 {
1504 pos = grub_strrchr(dudnode->dudpath[i].path, '.');
1505 grub_snprintf(tmpname, sizeof(tmpname), "ventoy/ventoy_dud%d%s", i, (pos ? pos : ".iso"));
1506 dud_size = dudnode->files[i].size;
1507 headlen = ventoy_cpio_newc_fill_head(buf, dud_size, dudnode->files[i].buf, tmpname);
1508 buf += headlen + ventoy_align(dud_size, 4);
1509 }
1510 }
1511
1512 /* step2: insert os param to cpio */
1513 headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
1514 padlen = sizeof(ventoy_os_param);
1515 g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len;
1516 mod = g_ventoy_cpio_size % 2048;
1517 if (mod)
1518 {
1519 g_ventoy_cpio_size += 2048 - mod;
1520 padlen += 2048 - mod;
1521 }
1522
1523 /* update os param data size, the data will be updated before chain boot */
1524 ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8);
1525 g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen;
1526
1527 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1528 g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen);
1529 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx");
1530
1531 grub_file_close(file);
1532 grub_file_close(archfile);
1533
1534 if (grub_strcmp(args[3], "busybox=64") == 0)
1535 {
1536 debug("cpio busybox proc %s\n", args[3]);
1537 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "64h");
1538 }
1539 else if (grub_strcmp(args[3], "busybox=a64") == 0)
1540 {
1541 debug("cpio busybox proc %s\n", args[3]);
1542 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "a64");
1543 }
1544 else if (grub_strcmp(args[3], "busybox=m64") == 0)
1545 {
1546 debug("cpio busybox proc %s\n", args[3]);
1547 ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "m64");
1548 }
1549
1550 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1551 }
1552
1553 grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
1554 {
1555 int mod;
1556 int bufsize;
1557 int namelen;
1558 int offset;
1559 char *name;
1560 grub_uint8_t *bufend;
1561 cpio_newc_header *head;
1562 grub_file_t file;
1563 const grub_uint8_t trailler[124] = {
1564 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1565 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1566 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
1567 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1568 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1569 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1570 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
1571 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
1572 };
1573
1574 (void)ctxt;
1575 (void)argc;
1576
1577 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], args[1]);
1578 if (!file)
1579 {
1580 return 1;
1581 }
1582
1583 grub_memset(g_ventoy_runtime_buf, 0, sizeof(ventoy_os_param));
1584 ventoy_fill_os_param(file, (ventoy_os_param *)g_ventoy_runtime_buf);
1585
1586 grub_file_close(file);
1587
1588 grub_memcpy(g_ventoy_initrd_head, trailler, sizeof(trailler));
1589 bufend = (grub_uint8_t *)g_ventoy_initrd_head + sizeof(trailler);
1590
1591 bufsize = (int)(bufend - g_ventoy_cpio_buf);
1592 mod = bufsize % 512;
1593 if (mod)
1594 {
1595 grub_memset(bufend, 0, 512 - mod);
1596 bufsize += 512 - mod;
1597 }
1598
1599 if (argc > 1 && grub_strcmp(args[2], "noinit") == 0)
1600 {
1601 head = (cpio_newc_header *)g_ventoy_cpio_buf;
1602 name = (char *)(head + 1);
1603
1604 while (grub_strcmp(name, "TRAILER!!!"))
1605 {
1606 if (grub_strcmp(name, "init") == 0)
1607 {
1608 grub_memcpy(name, "xxxx", 4);
1609 }
1610 else if (grub_strcmp(name, "linuxrc") == 0)
1611 {
1612 grub_memcpy(name, "vtoyxrc", 7);
1613 }
1614 else if (grub_strcmp(name, "sbin") == 0)
1615 {
1616 grub_memcpy(name, "vtoy", 4);
1617 }
1618 else if (grub_strcmp(name, "sbin/init") == 0)
1619 {
1620 grub_memcpy(name, "vtoy/vtoy", 9);
1621 }
1622
1623 namelen = ventoy_cpio_newc_get_int(head->c_namesize);
1624 offset = sizeof(cpio_newc_header) + namelen;
1625 offset = ventoy_align(offset, 4);
1626 offset += ventoy_cpio_newc_get_int(head->c_filesize);
1627 offset = ventoy_align(offset, 4);
1628
1629 head = (cpio_newc_header *)((char *)head + offset);
1630 name = (char *)(head + 1);
1631 }
1632 }
1633
1634 ventoy_memfile_env_set("ventoy_cpio", g_ventoy_cpio_buf, (ulonglong)bufsize);
1635
1636 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1637 }
1638
1639 grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1640 {
1641 int len = 0;
1642 int ventoy_compatible = 0;
1643 grub_uint32_t size = 0;
1644 grub_uint64_t isosize = 0;
1645 grub_uint32_t boot_catlog = 0;
1646 grub_uint32_t img_chunk_size = 0;
1647 grub_uint32_t override_count = 0;
1648 grub_uint32_t override_size = 0;
1649 grub_uint32_t virt_chunk_count = 0;
1650 grub_uint32_t virt_chunk_size = 0;
1651 grub_file_t file;
1652 grub_disk_t disk;
1653 const char *pLastChain = NULL;
1654 const char *compatible;
1655 ventoy_chain_head *chain;
1656
1657 (void)ctxt;
1658 (void)argc;
1659
1660 compatible = grub_env_get("ventoy_compatible");
1661 if (compatible && compatible[0] == 'Y')
1662 {
1663 ventoy_compatible = 1;
1664 }
1665
1666 if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL))
1667 {
1668 grub_printf("ventoy not ready\n");
1669 return 1;
1670 }
1671
1672 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1673 if (!file)
1674 {
1675 return 1;
1676 }
1677
1678 isosize = file->size;
1679
1680 len = (int)grub_strlen(args[0]);
1681 if (len >= 4 && 0 == grub_strcasecmp(args[0] + len - 4, ".img"))
1682 {
1683 debug("boot catlog %u for img file\n", boot_catlog);
1684 }
1685 else
1686 {
1687 boot_catlog = ventoy_get_iso_boot_catlog(file);
1688 if (boot_catlog)
1689 {
1690 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1691 {
1692 grub_env_set("LoadIsoEfiDriver", "on");
1693 }
1694 }
1695 else
1696 {
1697 if (ventoy_is_efi_os())
1698 {
1699 grub_env_set("LoadIsoEfiDriver", "on");
1700 }
1701 else
1702 {
1703 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1704 }
1705 }
1706 }
1707
1708 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1709
1710 override_count = ventoy_linux_get_override_chunk_count();
1711 virt_chunk_count = ventoy_linux_get_virt_chunk_count();
1712
1713 if (ventoy_compatible)
1714 {
1715 size = sizeof(ventoy_chain_head) + img_chunk_size;
1716 }
1717 else
1718 {
1719 override_size = ventoy_linux_get_override_chunk_size();
1720 virt_chunk_size = ventoy_linux_get_virt_chunk_size();
1721 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1722 }
1723
1724 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1725 if (pLastChain)
1726 {
1727 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1728 if (chain)
1729 {
1730 debug("free last chain memory %p\n", chain);
1731 grub_free(chain);
1732 }
1733 }
1734
1735 chain = ventoy_alloc_chain(size);
1736 if (!chain)
1737 {
1738 grub_printf("Failed to alloc chain linux memory size %u\n", size);
1739 grub_file_close(file);
1740 return 1;
1741 }
1742
1743 ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size);
1744
1745 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1746
1747 /* part 1: os parameter */
1748 g_ventoy_chain_type = ventoy_chain_linux;
1749 ventoy_fill_os_param(file, &(chain->os_param));
1750
1751 /* part 2: chain head */
1752 disk = file->device->disk;
1753 chain->disk_drive = disk->id;
1754 chain->disk_sector_size = (1 << disk->log_sector_size);
1755 chain->real_img_size_in_bytes = file->size;
1756 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1757 chain->boot_catalog = boot_catlog;
1758
1759 if (!ventoy_is_efi_os())
1760 {
1761 grub_file_seek(file, boot_catlog * 2048);
1762 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1763 }
1764
1765 /* part 3: image chunk */
1766 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1767 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1768 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1769
1770 if (ventoy_compatible)
1771 {
1772 return 0;
1773 }
1774
1775 /* part 4: override chunk */
1776 if (override_count > 0)
1777 {
1778 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1779 chain->override_chunk_num = override_count;
1780 ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
1781 }
1782
1783 /* part 5: virt chunk */
1784 if (virt_chunk_count > 0)
1785 {
1786 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1787 chain->virt_chunk_num = virt_chunk_count;
1788 ventoy_linux_fill_virt_data(isosize, chain);
1789 }
1790
1791 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1792 }
1793
1794 static char *ventoy_systemd_conf_tag(char *buf, const char *tag, int optional)
1795 {
1796 int taglen = 0;
1797 char *start = NULL;
1798 char *nextline = NULL;
1799
1800 taglen = grub_strlen(tag);
1801 for (start = buf; start; start = nextline)
1802 {
1803 nextline = ventoy_get_line(start);
1804 VTOY_SKIP_SPACE(start);
1805
1806 if (grub_strncmp(start, tag, taglen) == 0 && (start[taglen] == ' ' || start[taglen] == '\t'))
1807 {
1808 start += taglen;
1809 VTOY_SKIP_SPACE(start);
1810 return start;
1811 }
1812 }
1813
1814 if (optional == 0)
1815 {
1816 debug("tag<%s> NOT found\n", tag);
1817 }
1818 return NULL;
1819 }
1820
1821 static int ventoy_systemd_conf_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
1822 {
1823 int oldpos = 0;
1824 char *tag = NULL;
1825 char *bkbuf = NULL;
1826 char *filebuf = NULL;
1827 grub_file_t file = NULL;
1828 systemd_menu_ctx *ctx = (systemd_menu_ctx *)data;
1829
1830 debug("ventoy_systemd_conf_hook %s\n", filename);
1831
1832 if (info->dir || NULL == grub_strstr(filename, ".conf"))
1833 {
1834 return 0;
1835 }
1836
1837
1838 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/loader/entries/%s", ctx->dev, filename);
1839 if (!file)
1840 {
1841 return 0;
1842 }
1843
1844 filebuf = grub_zalloc(2 * file->size + 8);
1845 if (!filebuf)
1846 {
1847 goto out;
1848 }
1849
1850 bkbuf = filebuf + file->size + 4;
1851 grub_file_read(file, bkbuf, file->size);
1852
1853 oldpos = ctx->pos;
1854
1855 /* title --> menuentry */
1856 grub_memcpy(filebuf, bkbuf, file->size);
1857 tag = ventoy_systemd_conf_tag(filebuf, "title", 0);
1858 vtoy_check_goto_out(tag);
1859 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "menuentry \"%s\" {\n", tag);
1860
1861 /* linux xxx */
1862 grub_memcpy(filebuf, bkbuf, file->size);
1863 tag = ventoy_systemd_conf_tag(filebuf, "linux", 0);
1864 if (!tag)
1865 {
1866 ctx->pos = oldpos;
1867 goto out;
1868 }
1869 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, " echo \"Downloading kernel ...\"\n linux %s ", tag);
1870
1871 /* kernel options */
1872 grub_memcpy(filebuf, bkbuf, file->size);
1873 tag = ventoy_systemd_conf_tag(filebuf, "options", 0);
1874 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "%s \n", tag ? tag : "");
1875
1876
1877 /* initrd xxx xxx xxx */
1878 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, " echo \"Downloading initrd ...\"\n initrd ");
1879 grub_memcpy(filebuf, bkbuf, file->size);
1880 tag = ventoy_systemd_conf_tag(filebuf, "initrd", 1);
1881 while (tag)
1882 {
1883 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "%s ", tag);
1884 tag = ventoy_systemd_conf_tag(tag + grub_strlen(tag) + 1, "initrd", 1);
1885 }
1886
1887 vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "\n boot\n}\n");
1888
1889 out:
1890 grub_check_free(filebuf);
1891 grub_file_close(file);
1892 return 0;
1893 }
1894
1895 grub_err_t ventoy_cmd_linux_systemd_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1896 {
1897 static char *buf = NULL;
1898 grub_fs_t fs;
1899 char *device_name = NULL;
1900 grub_device_t dev = NULL;
1901 systemd_menu_ctx ctx;
1902
1903 (void)ctxt;
1904 (void)argc;
1905
1906 if (!buf)
1907 {
1908 buf = grub_malloc(VTOY_LINUX_SYSTEMD_MENU_MAX_BUF);
1909 if (!buf)
1910 {
1911 goto end;
1912 }
1913 }
1914
1915 device_name = grub_file_get_device_name(args[0]);
1916 if (!device_name)
1917 {
1918 debug("failed to get device name %s\n", args[0]);
1919 goto end;
1920 }
1921
1922 dev = grub_device_open(device_name);
1923 if (!dev)
1924 {
1925 debug("failed to open device %s\n", device_name);
1926 goto end;
1927 }
1928
1929 fs = grub_fs_probe(dev);
1930 if (!fs)
1931 {
1932 debug("failed to probe fs %d\n", grub_errno);
1933 goto end;
1934 }
1935
1936 ctx.dev = args[0];
1937 ctx.buf = buf;
1938 ctx.pos = 0;
1939 ctx.len = VTOY_LINUX_SYSTEMD_MENU_MAX_BUF;
1940 fs->fs_dir(dev, "/loader/entries", ventoy_systemd_conf_hook, &ctx);
1941
1942 ventoy_memfile_env_set(args[1], buf, (ulonglong)(ctx.pos));
1943
1944 end:
1945 grub_check_free(device_name);
1946 check_free(dev, grub_device_close);
1947 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1948 }
1949
1950 static int ventoy_limine_path_convert(char *path)
1951 {
1952 char newpath[256] = {0};
1953
1954 if (grub_strncmp(path, "boot://2/", 9) == 0)
1955 {
1956 grub_snprintf(newpath, sizeof(newpath), "(vtimghd,2)/%s", path + 9);
1957 }
1958 else if (grub_strncmp(path, "boot://1/", 9) == 0)
1959 {
1960 grub_snprintf(newpath, sizeof(newpath), "(vtimghd,1)/%s", path + 9);
1961 }
1962
1963 if (newpath[0])
1964 {
1965 grub_snprintf(path, 1024, "%s", newpath);
1966 }
1967
1968 return 0;
1969 }
1970
1971 grub_err_t ventoy_cmd_linux_limine_menu(grub_extcmd_context_t ctxt, int argc, char **args)
1972 {
1973 int pos = 0;
1974 int sub = 0;
1975 int len = VTOY_LINUX_SYSTEMD_MENU_MAX_BUF;
1976 char *filebuf = NULL;
1977 char *start = NULL;
1978 char *nextline = NULL;
1979 grub_file_t file = NULL;
1980 char *title = NULL;
1981 char *kernel = NULL;
1982 char *initrd = NULL;
1983 char *param = NULL;
1984 static char *buf = NULL;
1985
1986 (void)ctxt;
1987 (void)argc;
1988
1989 if (!buf)
1990 {
1991 buf = grub_malloc(len + 4 * 1024);
1992 if (!buf)
1993 {
1994 goto end;
1995 }
1996 }
1997
1998 title = buf + len;
1999 kernel = title + 1024;
2000 initrd = kernel + 1024;
2001 param = initrd + 1024;
2002
2003 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, args[0]);
2004 if (!file)
2005 {
2006 return 0;
2007 }
2008
2009 filebuf = grub_zalloc(file->size + 8);
2010 if (!filebuf)
2011 {
2012 goto end;
2013 }
2014
2015 grub_file_read(file, filebuf, file->size);
2016 grub_file_close(file);
2017
2018
2019 title[0] = kernel[0] = initrd[0] = param[0] = 0;
2020 for (start = filebuf; start; start = nextline)
2021 {
2022 nextline = ventoy_get_line(start);
2023 VTOY_SKIP_SPACE(start);
2024
2025 if (start[0] == ':')
2026 {
2027 if (start[1] == ':')
2028 {
2029 grub_snprintf(title, 1024, "%s", start + 2);
2030 }
2031 else
2032 {
2033 if (sub)
2034 {
2035 vtoy_len_ssprintf(buf, pos, len, "}\n");
2036 sub = 0;
2037 }
2038
2039 if (nextline && nextline[0] == ':' && nextline[1] == ':')
2040 {
2041 vtoy_len_ssprintf(buf, pos, len, "submenu \"[+] %s\" {\n", start + 2);
2042 sub = 1;
2043 title[0] = 0;
2044 }
2045 else
2046 {
2047 grub_snprintf(title, 1024, "%s", start + 1);
2048 }
2049 }
2050 }
2051 else if (grub_strncmp(start, "KERNEL_PATH=", 12) == 0)
2052 {
2053 grub_snprintf(kernel, 1024, "%s", start + 12);
2054 }
2055 else if (grub_strncmp(start, "MODULE_PATH=", 12) == 0)
2056 {
2057 grub_snprintf(initrd, 1024, "%s", start + 12);
2058 }
2059 else if (grub_strncmp(start, "KERNEL_CMDLINE=", 15) == 0)
2060 {
2061 grub_snprintf(param, 1024, "%s", start + 15);
2062 }
2063
2064 if (title[0] && kernel[0] && initrd[0] && param[0])
2065 {
2066 ventoy_limine_path_convert(kernel);
2067 ventoy_limine_path_convert(initrd);
2068
2069 vtoy_len_ssprintf(buf, pos, len, "menuentry \"%s\" {\n", title);
2070 vtoy_len_ssprintf(buf, pos, len, " echo \"Downloading kernel ...\"\n linux %s %s\n", kernel, param);
2071 vtoy_len_ssprintf(buf, pos, len, " echo \"Downloading initrd ...\"\n initrd %s\n", initrd);
2072 vtoy_len_ssprintf(buf, pos, len, "}\n");
2073
2074 title[0] = kernel[0] = initrd[0] = param[0] = 0;
2075 }
2076 }
2077
2078 if (sub)
2079 {
2080 vtoy_len_ssprintf(buf, pos, len, "}\n");
2081 sub = 0;
2082 }
2083
2084 ventoy_memfile_env_set(args[1], buf, (ulonglong)pos);
2085
2086 end:
2087 grub_check_free(filebuf);
2088 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2089 }
2090