]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
ddd7499aa97725effc15fea86c8c1e8f79d7d4ca
[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
42 static char * ventoy_get_line(char *start)
43 {
44 if (start == NULL)
45 {
46 return NULL;
47 }
48
49 while (*start && *start != '\n')
50 {
51 start++;
52 }
53
54 if (*start == 0)
55 {
56 return NULL;
57 }
58 else
59 {
60 *start = 0;
61 return start + 1;
62 }
63 }
64
65 static initrd_info * ventoy_find_initrd_by_name(initrd_info *list, const char *name)
66 {
67 initrd_info *node = list;
68
69 while (node)
70 {
71 if (grub_strcmp(node->name, name) == 0)
72 {
73 return node;
74 }
75 node = node->next;
76 }
77
78 return NULL;
79 }
80
81 grub_err_t ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args)
82 {
83 initrd_info *node = g_initrd_img_list;
84 initrd_info *next;
85
86 (void)ctxt;
87 (void)argc;
88 (void)args;
89
90 while (node)
91 {
92 next = node->next;
93 grub_free(node);
94 node = next;
95 }
96
97 g_initrd_img_list = NULL;
98 g_initrd_img_tail = NULL;
99 g_initrd_img_count = 0;
100 g_valid_initrd_count = 0;
101
102 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
103 }
104
105 grub_err_t ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args)
106 {
107 int i = 0;
108 initrd_info *node = g_initrd_img_list;
109
110 (void)ctxt;
111 (void)argc;
112 (void)args;
113
114 grub_printf("###################\n");
115 grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count);
116
117 while (node)
118 {
119 grub_printf("%s ", node->size > 0 ? "*" : " ");
120 grub_printf("%02u %s offset:%llu size:%llu \n", i++, node->name, (unsigned long long)node->offset,
121 (unsigned long long)node->size);
122 node = node->next;
123 }
124
125 grub_printf("###################\n");
126
127 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
128 }
129
130 static void ventoy_parse_directory(char *path, char *dir, int buflen)
131 {
132 int end;
133 char *pos;
134
135 pos = grub_strstr(path, ")");
136 if (!pos)
137 {
138 pos = path;
139 }
140
141 end = grub_snprintf(dir, buflen, "%s", pos + 1);
142 while (end > 0)
143 {
144 if (dir[end] == '/')
145 {
146 dir[end + 1] = 0;
147 break;
148 }
149 end--;
150 }
151 }
152
153 static grub_err_t ventoy_isolinux_initrd_collect(grub_file_t file, const char *prefix)
154 {
155 int i = 0;
156 int offset;
157 int prefixlen = 0;
158 char *buf = NULL;
159 char *pos = NULL;
160 char *start = NULL;
161 char *nextline = NULL;
162 initrd_info *img = NULL;
163
164 prefixlen = grub_strlen(prefix);
165
166 buf = grub_zalloc(file->size + 2);
167 if (!buf)
168 {
169 return 0;
170 }
171
172 grub_file_read(file, buf, file->size);
173
174 for (start = buf; start; start = nextline)
175 {
176 nextline = ventoy_get_line(start);
177
178 while (ventoy_isspace(*start))
179 {
180 start++;
181 }
182
183 offset = 7; // strlen("initrd=") or "INITRD " or "initrd "
184 pos = grub_strstr(start, "initrd=");
185 if (pos == NULL)
186 {
187 pos = start;
188
189 if (grub_strncmp(start, "INITRD", 6) != 0 && grub_strncmp(start, "initrd", 6) != 0)
190 {
191 if (grub_strstr(start, "xen") &&
192 ((pos = grub_strstr(start, "--- /install.img")) != NULL ||
193 (pos = grub_strstr(start, "--- initrd.img")) != NULL
194 ))
195 {
196 offset = 4; // "--- "
197 }
198 else
199 {
200 continue;
201 }
202 }
203 }
204
205 pos += offset;
206
207 while (1)
208 {
209 i = 0;
210 img = grub_zalloc(sizeof(initrd_info));
211 if (!img)
212 {
213 break;
214 }
215
216 if (*pos != '/')
217 {
218 grub_strcpy(img->name, prefix);
219 i = prefixlen;
220 }
221
222 while (i < 255 && (0 == ventoy_is_word_end(*pos)))
223 {
224 img->name[i++] = *pos++;
225 }
226
227 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
228 {
229 grub_free(img);
230 }
231 else
232 {
233 if (g_initrd_img_list)
234 {
235 img->prev = g_initrd_img_tail;
236 g_initrd_img_tail->next = img;
237 }
238 else
239 {
240 g_initrd_img_list = img;
241 }
242
243 g_initrd_img_tail = img;
244 g_initrd_img_count++;
245 }
246
247 if (*pos == ',')
248 {
249 pos++;
250 }
251 else
252 {
253 break;
254 }
255 }
256 }
257
258 grub_free(buf);
259 return GRUB_ERR_NONE;
260 }
261
262 static int ventoy_isolinux_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
263 {
264 grub_file_t file = NULL;
265 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
266
267 (void)info;
268
269 if (NULL == grub_strstr(filename, ".cfg") && NULL == grub_strstr(filename, ".CFG"))
270 {
271 return 0;
272 }
273
274 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
275
276 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ctx->path_prefix, filename);
277 if (!file)
278 {
279 return 0;
280 }
281
282 ventoy_isolinux_initrd_collect(file, ctx->dir_prefix);
283 grub_file_close(file);
284
285 return 0;
286 }
287
288 grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
289 {
290 grub_fs_t fs;
291 grub_device_t dev = NULL;
292 char *device_name = NULL;
293 ventoy_initrd_ctx ctx;
294 char directory[256];
295
296 (void)ctxt;
297 (void)argc;
298
299 device_name = grub_file_get_device_name(args[0]);
300 if (!device_name)
301 {
302 goto end;
303 }
304
305 dev = grub_device_open(device_name);
306 if (!dev)
307 {
308 goto end;
309 }
310
311 fs = grub_fs_probe(dev);
312 if (!fs)
313 {
314 goto end;
315 }
316
317 debug("isolinux initrd collect %s\n", args[0]);
318
319 ventoy_parse_directory(args[0], directory, sizeof(directory) - 1);
320 ctx.path_prefix = args[0];
321 ctx.dir_prefix = (argc > 1) ? args[1] : directory;
322
323 debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx.path_prefix, ctx.dir_prefix);
324
325 fs->fs_dir(dev, directory, ventoy_isolinux_initrd_hook, &ctx);
326
327 end:
328 check_free(device_name, grub_free);
329 check_free(dev, grub_device_close);
330
331 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
332 }
333
334 static grub_err_t ventoy_grub_cfg_initrd_collect(const char *fileName)
335 {
336 int i = 0;
337 grub_file_t file = NULL;
338 char *buf = NULL;
339 char *start = NULL;
340 char *nextline = NULL;
341 initrd_info *img = NULL;
342
343 debug("grub initrd collect %s\n", fileName);
344
345 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", fileName);
346 if (!file)
347 {
348 return 0;
349 }
350
351 buf = grub_zalloc(file->size + 2);
352 if (!buf)
353 {
354 grub_file_close(file);
355 return 0;
356 }
357
358 grub_file_read(file, buf, file->size);
359
360 for (start = buf; start; start = nextline)
361 {
362 nextline = ventoy_get_line(start);
363
364 while (ventoy_isspace(*start))
365 {
366 start++;
367 }
368
369 if (grub_strncmp(start, "initrd", 6) != 0)
370 {
371 continue;
372 }
373
374 start += 6;
375 while (*start && (!ventoy_isspace(*start)))
376 {
377 start++;
378 }
379
380 while (ventoy_isspace(*start))
381 {
382 start++;
383 }
384
385 while (*start)
386 {
387 img = grub_zalloc(sizeof(initrd_info));
388 if (!img)
389 {
390 break;
391 }
392
393 for (i = 0; i < 255 && (0 == ventoy_is_word_end(*start)); i++)
394 {
395 img->name[i] = *start++;
396 }
397
398 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
399 {
400 grub_free(img);
401 }
402 else
403 {
404 if (g_initrd_img_list)
405 {
406 img->prev = g_initrd_img_tail;
407 g_initrd_img_tail->next = img;
408 }
409 else
410 {
411 g_initrd_img_list = img;
412 }
413
414 g_initrd_img_tail = img;
415 g_initrd_img_count++;
416 }
417
418 if (*start == ' ' || *start == '\t')
419 {
420 while (ventoy_isspace(*start))
421 {
422 start++;
423 }
424 }
425 else
426 {
427 break;
428 }
429 }
430 }
431
432 grub_free(buf);
433 grub_file_close(file);
434
435 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
436 }
437
438 static int ventoy_grub_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data)
439 {
440 char filePath[256];
441 ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data;
442
443 (void)info;
444
445 debug("ventoy_grub_initrd_hook %s\n", filename);
446
447 if (NULL == grub_strstr(filename, ".cfg") &&
448 NULL == grub_strstr(filename, ".CFG") &&
449 NULL == grub_strstr(filename, ".conf"))
450 {
451 return 0;
452 }
453
454 debug("init hook dir <%s%s>\n", ctx->path_prefix, filename);
455
456 grub_snprintf(filePath, sizeof(filePath) - 1, "%s%s", ctx->dir_prefix, filename);
457 ventoy_grub_cfg_initrd_collect(filePath);
458
459 return 0;
460 }
461
462 grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args)
463 {
464 grub_fs_t fs;
465 grub_device_t dev = NULL;
466 char *device_name = NULL;
467 ventoy_initrd_ctx ctx;
468
469 (void)ctxt;
470 (void)argc;
471
472 if (argc != 2)
473 {
474 return 0;
475 }
476
477 debug("grub initrd collect %s %s\n", args[0], args[1]);
478
479 if (grub_strcmp(args[0], "file") == 0)
480 {
481 return ventoy_grub_cfg_initrd_collect(args[1]);
482 }
483
484 device_name = grub_file_get_device_name(args[1]);
485 if (!device_name)
486 {
487 debug("failed to get device name %s\n", args[1]);
488 goto end;
489 }
490
491 dev = grub_device_open(device_name);
492 if (!dev)
493 {
494 debug("failed to open device %s\n", device_name);
495 goto end;
496 }
497
498 fs = grub_fs_probe(dev);
499 if (!fs)
500 {
501 debug("failed to probe fs %d\n", grub_errno);
502 goto end;
503 }
504
505 ctx.dir_prefix = args[1];
506 ctx.path_prefix = grub_strstr(args[1], device_name);
507 if (ctx.path_prefix)
508 {
509 ctx.path_prefix += grub_strlen(device_name) + 1;
510 }
511 else
512 {
513 ctx.path_prefix = args[1];
514 }
515
516 debug("ctx.path_prefix:<%s>\n", ctx.path_prefix);
517
518 fs->fs_dir(dev, ctx.path_prefix, ventoy_grub_initrd_hook, &ctx);
519
520 end:
521 check_free(device_name, grub_free);
522 check_free(dev, grub_device_close);
523
524
525 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
526 }
527
528 grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args)
529 {
530 initrd_info *img = NULL;
531
532 (void)ctxt;
533 (void)argc;
534
535 debug("ventoy_cmd_specify_initrd_file %s\n", args[0]);
536
537 img = grub_zalloc(sizeof(initrd_info));
538 if (!img)
539 {
540 return 1;
541 }
542
543 grub_strncpy(img->name, args[0], sizeof(img->name));
544 if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name))
545 {
546 debug("%s is already exist\n", args[0]);
547 grub_free(img);
548 }
549 else
550 {
551 if (g_initrd_img_list)
552 {
553 img->prev = g_initrd_img_tail;
554 g_initrd_img_tail->next = img;
555 }
556 else
557 {
558 g_initrd_img_list = img;
559 }
560
561 g_initrd_img_tail = img;
562 g_initrd_img_count++;
563 }
564
565 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
566 }
567
568 static void ventoy_cpio_newc_fill_int(grub_uint32_t value, char *buf, int buflen)
569 {
570 int i;
571 int len;
572 char intbuf[32];
573
574 len = grub_snprintf(intbuf, sizeof(intbuf), "%x", value);
575
576 for (i = 0; i < buflen; i++)
577 {
578 buf[i] = '0';
579 }
580
581 if (len > buflen)
582 {
583 grub_printf("int buf len overflow %d %d\n", len, buflen);
584 }
585 else
586 {
587 grub_memcpy(buf + buflen - len, intbuf, len);
588 }
589 }
590
591 int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name)
592 {
593 int namelen = 0;
594 int headlen = 0;
595 static grub_uint32_t cpio_ino = 0xFFFFFFF0;
596 cpio_newc_header *cpio = (cpio_newc_header *)buf;
597
598 namelen = grub_strlen(name) + 1;
599 headlen = sizeof(cpio_newc_header) + namelen;
600 headlen = ventoy_align(headlen, 4);
601
602 grub_memset(cpio, '0', sizeof(cpio_newc_header));
603 grub_memset(cpio + 1, 0, headlen - sizeof(cpio_newc_header));
604
605 grub_memcpy(cpio->c_magic, "070701", 6);
606 ventoy_cpio_newc_fill_int(cpio_ino--, cpio->c_ino, 8);
607 ventoy_cpio_newc_fill_int(0100777, cpio->c_mode, 8);
608 ventoy_cpio_newc_fill_int(1, cpio->c_nlink, 8);
609 ventoy_cpio_newc_fill_int(filesize, cpio->c_filesize, 8);
610 ventoy_cpio_newc_fill_int(namelen, cpio->c_namesize, 8);
611 grub_memcpy(cpio + 1, name, namelen);
612
613 if (filedata)
614 {
615 grub_memcpy((char *)cpio + headlen, filedata, filesize);
616 }
617
618 return headlen;
619 }
620
621 static grub_uint32_t ventoy_linux_get_virt_chunk_size(void)
622 {
623 return (sizeof(ventoy_virt_chunk) + g_ventoy_cpio_size) * g_valid_initrd_count;
624 }
625
626 static void ventoy_linux_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
627 {
628 int id = 0;
629 initrd_info *node;
630 grub_uint64_t sector;
631 grub_uint32_t offset;
632 grub_uint32_t cpio_secs;
633 grub_uint32_t initrd_secs;
634 char *override;
635 ventoy_virt_chunk *cur;
636 char name[32];
637
638 override = (char *)chain + chain->virt_chunk_offset;
639 sector = (isosize + 2047) / 2048;
640 cpio_secs = g_ventoy_cpio_size / 2048;
641
642 offset = g_valid_initrd_count * sizeof(ventoy_virt_chunk);
643 cur = (ventoy_virt_chunk *)override;
644
645 for (node = g_initrd_img_list; node; node = node->next)
646 {
647 if (node->size == 0)
648 {
649 continue;
650 }
651
652 initrd_secs = (grub_uint32_t)((node->size + 2047) / 2048);
653
654 cur->mem_sector_start = sector;
655 cur->mem_sector_end = cur->mem_sector_start + cpio_secs;
656 cur->mem_sector_offset = offset;
657 cur->remap_sector_start = cur->mem_sector_end;
658 cur->remap_sector_end = cur->remap_sector_start + initrd_secs;
659 cur->org_sector_start = (grub_uint32_t)(node->offset / 2048);
660
661 grub_memcpy(g_ventoy_runtime_buf, &chain->os_param, sizeof(ventoy_os_param));
662
663 grub_memset(name, 0, 16);
664 grub_snprintf(name, sizeof(name), "initrd%03d", ++id);
665
666 grub_memcpy(g_ventoy_initrd_head + 1, name, 16);
667 ventoy_cpio_newc_fill_int((grub_uint32_t)node->size, g_ventoy_initrd_head->c_filesize, 8);
668
669 grub_memcpy(override + offset, g_ventoy_cpio_buf, g_ventoy_cpio_size);
670
671 chain->virt_img_size_in_bytes += g_ventoy_cpio_size + initrd_secs * 2048;
672
673 offset += g_ventoy_cpio_size;
674 sector += cpio_secs + initrd_secs;
675 cur++;
676 }
677
678 return;
679 }
680
681 static grub_uint32_t ventoy_linux_get_override_chunk_size(void)
682 {
683 return sizeof(ventoy_override_chunk) * g_valid_initrd_count;
684 }
685
686 static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override)
687 {
688 initrd_info *node;
689 grub_uint32_t mod;
690 grub_uint32_t newlen;
691 grub_uint64_t sector;
692 ventoy_override_chunk *cur;
693
694 sector = (isosize + 2047) / 2048;
695
696 cur = (ventoy_override_chunk *)override;
697 for (node = g_initrd_img_list; node; node = node->next)
698 {
699 if (node->size == 0)
700 {
701 continue;
702 }
703
704 newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
705 mod = newlen % 4;
706 if (mod > 0)
707 {
708 newlen += 4 - mod;
709 }
710
711 if (node->iso_type == 0)
712 {
713 ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)node->override_data;
714
715 node->override_length = sizeof(ventoy_iso9660_override);
716 dirent->first_sector = (grub_uint32_t)sector;
717 dirent->size = newlen;
718 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
719 dirent->size_be = grub_swap_bytes32(dirent->size);
720
721 sector += (dirent->size + 2047) / 2048;
722 }
723 else
724 {
725 ventoy_udf_override *udf = (ventoy_udf_override *)node->override_data;
726
727 node->override_length = sizeof(ventoy_udf_override);
728 udf->length = newlen;
729 udf->position = (grub_uint32_t)sector - node->udf_start_block;
730
731 sector += (udf->length + 2047) / 2048;
732 }
733
734 cur->img_offset = node->override_offset;
735 cur->override_size = node->override_length;
736 grub_memcpy(cur->override_data, node->override_data, cur->override_size);
737 cur++;
738 }
739
740 return;
741 }
742
743 grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
744 {
745 char buf[32] = {0};
746
747 (void)ctxt;
748 (void)argc;
749 (void)args;
750
751 if (argc == 1)
752 {
753 grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count);
754 grub_env_set(args[0], buf);
755 }
756
757 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
758 }
759
760 grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
761 {
762 char buf[32] = {0};
763
764 (void)ctxt;
765 (void)argc;
766 (void)args;
767
768 if (argc == 1)
769 {
770 grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count);
771 grub_env_set(args[0], buf);
772 }
773
774 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
775 }
776
777 static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt)
778 {
779 int data;
780 int filtbysize = 1;
781 int sizefilt = 0;
782 grub_file_t file;
783 initrd_info *node;
784
785 debug("ventoy_linux_locate_initrd %d\n", filt);
786
787 g_valid_initrd_count = 0;
788
789 if (grub_env_get("INITRD_NO_SIZE_FILT"))
790 {
791 filtbysize = 0;
792 }
793
794 for (node = g_initrd_img_list; node; node = node->next)
795 {
796 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name);
797 if (!file)
798 {
799 continue;
800 }
801
802 debug("file <%s> size:%d\n", node->name, (int)file->size);
803
804 /* initrd file too small */
805 if (filtbysize
806 && (NULL == grub_strstr(node->name, "minirt.gz"))
807 && (NULL == grub_strstr(node->name, "initrd.xz"))
808 )
809 {
810 if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048)
811 {
812 debug("file size too small %d\n", (int)g_ventoy_cpio_size);
813 grub_file_close(file);
814 sizefilt++;
815 continue;
816 }
817 }
818
819 if (grub_strcmp(file->fs->name, "iso9660") == 0)
820 {
821 node->iso_type = 0;
822 node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
823
824 grub_file_read(file, &data, 1); // just read for hook trigger
825 node->offset = grub_iso9660_get_last_read_pos(file);
826 }
827 else
828 {
829 /* TBD */
830 }
831
832 node->size = file->size;
833 g_valid_initrd_count++;
834
835 grub_file_close(file);
836 }
837
838 *filtcnt = sizefilt;
839
840 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
841 }
842
843
844 grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args)
845 {
846 int index = 0;
847 char buf[32];
848 initrd_info *node = NULL;
849
850 (void)ctxt;
851 (void)argc;
852 (void)args;
853
854 if (argc != 1)
855 {
856 return 1;
857 }
858
859 if (g_initrd_img_count == 1)
860 {
861 ventoy_set_env(args[0], "0");
862 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
863 }
864
865 for (node = g_initrd_img_list; node; node = node->next)
866 {
867 if (node->size <= 0)
868 {
869 continue;
870 }
871
872 if (grub_strstr(node->name, "ucode") || grub_strstr(node->name, "-firmware"))
873 {
874 index++;
875 continue;
876 }
877
878 grub_snprintf(buf, sizeof(buf), "%d", index);
879 ventoy_set_env(args[0], buf);
880 break;
881 }
882
883 debug("main initrd index:%d\n", index);
884
885 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
886 }
887
888 grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
889 {
890 int sizefilt = 0;
891
892 (void)ctxt;
893 (void)argc;
894 (void)args;
895
896 ventoy_linux_locate_initrd(1, &sizefilt);
897
898 if (g_valid_initrd_count == 0 && sizefilt > 0)
899 {
900 ventoy_linux_locate_initrd(0, &sizefilt);
901 }
902
903 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
904 }
905
906 grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
907 {
908 int rc;
909 char *template_file = NULL;
910 char *template_buf = NULL;
911 char *persistent_buf = NULL;
912 grub_uint8_t *buf = NULL;
913 grub_uint32_t mod;
914 grub_uint32_t headlen;
915 grub_uint32_t initrd_head_len;
916 grub_uint32_t padlen;
917 grub_uint32_t img_chunk_size;
918 grub_uint32_t template_size = 0;
919 grub_uint32_t persistent_size = 0;
920 grub_file_t file;
921 grub_file_t scriptfile;
922 ventoy_img_chunk_list chunk_list;
923
924 (void)ctxt;
925 (void)argc;
926
927 if (argc != 3)
928 {
929 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name);
930 }
931
932 if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0)
933 {
934 return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n");
935 }
936
937 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
938
939 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
940 if (!file)
941 {
942 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
943 }
944
945 if (g_ventoy_cpio_buf)
946 {
947 grub_free(g_ventoy_cpio_buf);
948 g_ventoy_cpio_buf = NULL;
949 g_ventoy_cpio_size = 0;
950 }
951
952 rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list);
953 if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
954 {
955 persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
956 persistent_buf = (char *)(chunk_list.chunk);
957 }
958
959 template_file = ventoy_plugin_get_cur_install_template(args[1]);
960 if (template_file)
961 {
962 debug("auto install template: <%s>\n", template_file);
963 scriptfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], template_file);
964 if (scriptfile)
965 {
966 debug("auto install script size %d\n", (int)scriptfile->size);
967 template_size = scriptfile->size;
968 template_buf = grub_malloc(template_size);
969 if (template_buf)
970 {
971 grub_file_read(scriptfile, template_buf, template_size);
972 }
973
974 grub_file_close(scriptfile);
975 }
976 else
977 {
978 debug("Failed to open install script %s%s\n", args[2], template_file);
979 }
980 }
981 else
982 {
983 debug("auto install script skipped or not configed %s\n", args[1]);
984 }
985
986 g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + persistent_size + img_chunk_size);
987 if (NULL == g_ventoy_cpio_buf)
988 {
989 grub_file_close(file);
990 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size + 4096 + img_chunk_size);
991 }
992
993 grub_file_read(file, g_ventoy_cpio_buf, file->size);
994
995 buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4);
996 while (*((grub_uint32_t *)buf) != 0x37303730)
997 {
998 buf -= 4;
999 }
1000
1001 /* get initrd head len */
1002 initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx");
1003
1004 /* step1: insert image chunk data to cpio */
1005 headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map");
1006 buf += headlen + ventoy_align(img_chunk_size, 4);
1007
1008 if (template_buf)
1009 {
1010 headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall");
1011 buf += headlen + ventoy_align(template_size, 4);
1012 }
1013
1014 if (persistent_size > 0 && persistent_buf)
1015 {
1016 headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
1017 buf += headlen + ventoy_align(persistent_size, 4);
1018
1019 grub_free(persistent_buf);
1020 persistent_buf = NULL;
1021 }
1022
1023 /* step2: insert os param to cpio */
1024 headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
1025 padlen = sizeof(ventoy_os_param);
1026 g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len;
1027 mod = g_ventoy_cpio_size % 2048;
1028 if (mod)
1029 {
1030 g_ventoy_cpio_size += 2048 - mod;
1031 padlen += 2048 - mod;
1032 }
1033
1034 /* update os param data size, the data will be updated before chain boot */
1035 ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8);
1036 g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen;
1037
1038 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
1039 g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen);
1040 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx");
1041
1042 grub_file_close(file);
1043
1044 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1045 }
1046
1047
1048 grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1049 {
1050 int ventoy_compatible = 0;
1051 grub_uint32_t size = 0;
1052 grub_uint64_t isosize = 0;
1053 grub_uint32_t boot_catlog = 0;
1054 grub_uint32_t img_chunk_size = 0;
1055 grub_uint32_t override_size = 0;
1056 grub_uint32_t virt_chunk_size = 0;
1057 grub_file_t file;
1058 grub_disk_t disk;
1059 const char *pLastChain = NULL;
1060 const char *compatible;
1061 ventoy_chain_head *chain;
1062 char envbuf[64];
1063
1064 (void)ctxt;
1065 (void)argc;
1066
1067 compatible = grub_env_get("ventoy_compatible");
1068 if (compatible && compatible[0] == 'Y')
1069 {
1070 ventoy_compatible = 1;
1071 }
1072
1073 if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL))
1074 {
1075 grub_printf("ventoy not ready\n");
1076 return 1;
1077 }
1078
1079 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1080 if (!file)
1081 {
1082 return 1;
1083 }
1084
1085 isosize = file->size;
1086
1087 boot_catlog = ventoy_get_iso_boot_catlog(file);
1088 if (boot_catlog)
1089 {
1090 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1091 {
1092 grub_env_set("LoadIsoEfiDriver", "on");
1093 }
1094 }
1095 else
1096 {
1097 if (ventoy_is_efi_os())
1098 {
1099 grub_env_set("LoadIsoEfiDriver", "on");
1100 }
1101 else
1102 {
1103 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1104 }
1105 }
1106
1107 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1108
1109 if (ventoy_compatible)
1110 {
1111 size = sizeof(ventoy_chain_head) + img_chunk_size;
1112 }
1113 else
1114 {
1115 override_size = ventoy_linux_get_override_chunk_size();
1116 virt_chunk_size = ventoy_linux_get_virt_chunk_size();
1117 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1118 }
1119
1120 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1121 if (pLastChain)
1122 {
1123 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1124 if (chain)
1125 {
1126 debug("free last chain memory %p\n", chain);
1127 grub_free(chain);
1128 }
1129 }
1130
1131 chain = grub_malloc(size);
1132 if (!chain)
1133 {
1134 grub_printf("Failed to alloc chain memory size %u\n", size);
1135 grub_file_close(file);
1136 return 1;
1137 }
1138
1139 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1140 grub_env_set("vtoy_chain_mem_addr", envbuf);
1141 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1142 grub_env_set("vtoy_chain_mem_size", envbuf);
1143
1144 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1145
1146 /* part 1: os parameter */
1147 g_ventoy_chain_type = 0;
1148 ventoy_fill_os_param(file, &(chain->os_param));
1149
1150 /* part 2: chain head */
1151 disk = file->device->disk;
1152 chain->disk_drive = disk->id;
1153 chain->disk_sector_size = (1 << disk->log_sector_size);
1154 chain->real_img_size_in_bytes = file->size;
1155 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1156 chain->boot_catalog = boot_catlog;
1157
1158 if (!ventoy_is_efi_os())
1159 {
1160 grub_file_seek(file, boot_catlog * 2048);
1161 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1162 }
1163
1164 /* part 3: image chunk */
1165 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1166 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1167 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1168
1169 if (ventoy_compatible)
1170 {
1171 return 0;
1172 }
1173
1174 if (g_valid_initrd_count == 0)
1175 {
1176 return 0;
1177 }
1178
1179 /* part 4: override chunk */
1180 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1181 chain->override_chunk_num = g_valid_initrd_count;
1182 ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
1183
1184 /* part 5: virt chunk */
1185 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1186 chain->virt_chunk_num = g_valid_initrd_count;
1187 ventoy_linux_fill_virt_data(isosize, chain);
1188
1189 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1190 }
1191