]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/ventoy/ventoy_linux.c
Update PhyDrive.c
[Ventoy.git] / GRUB2 / 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_uint64_t sector;
690 ventoy_override_chunk *cur;
691
692 sector = (isosize + 2047) / 2048;
693
694 cur = (ventoy_override_chunk *)override;
695 for (node = g_initrd_img_list; node; node = node->next)
696 {
697 if (node->size == 0)
698 {
699 continue;
700 }
701
702 if (node->iso_type == 0)
703 {
704 ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)node->override_data;
705
706 node->override_length = sizeof(ventoy_iso9660_override);
707 dirent->first_sector = (grub_uint32_t)sector;
708 dirent->size = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
709 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
710 dirent->size_be = grub_swap_bytes32(dirent->size);
711
712 sector += (dirent->size + 2047) / 2048;
713 }
714 else
715 {
716 ventoy_udf_override *udf = (ventoy_udf_override *)node->override_data;
717
718 node->override_length = sizeof(ventoy_udf_override);
719 udf->length = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
720 udf->position = (grub_uint32_t)sector - node->udf_start_block;
721
722 sector += (udf->length + 2047) / 2048;
723 }
724
725 cur->img_offset = node->override_offset;
726 cur->override_size = node->override_length;
727 grub_memcpy(cur->override_data, node->override_data, cur->override_size);
728 cur++;
729 }
730
731 return;
732 }
733
734 grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
735 {
736 char buf[32] = {0};
737
738 (void)ctxt;
739 (void)argc;
740 (void)args;
741
742 if (argc == 1)
743 {
744 grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count);
745 grub_env_set(args[0], buf);
746 }
747
748 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
749 }
750
751 grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args)
752 {
753 char buf[32] = {0};
754
755 (void)ctxt;
756 (void)argc;
757 (void)args;
758
759 if (argc == 1)
760 {
761 grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count);
762 grub_env_set(args[0], buf);
763 }
764
765 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
766 }
767
768 static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt)
769 {
770 int data;
771 int filtbysize = 1;
772 int sizefilt = 0;
773 grub_file_t file;
774 initrd_info *node;
775
776 debug("ventoy_linux_locate_initrd %d\n", filt);
777
778 g_valid_initrd_count = 0;
779
780 if (grub_env_get("INITRD_NO_SIZE_FILT"))
781 {
782 filtbysize = 0;
783 }
784
785 for (node = g_initrd_img_list; node; node = node->next)
786 {
787 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name);
788 if (!file)
789 {
790 continue;
791 }
792
793 debug("file <%s> size:%d\n", node->name, (int)file->size);
794
795 /* initrd file too small */
796 if (filtbysize
797 && (NULL == grub_strstr(node->name, "minirt.gz"))
798 && (NULL == grub_strstr(node->name, "initrd.xz"))
799 )
800 {
801 if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048)
802 {
803 debug("file size too small %d\n", (int)g_ventoy_cpio_size);
804 grub_file_close(file);
805 sizefilt++;
806 continue;
807 }
808 }
809
810 if (grub_strcmp(file->fs->name, "iso9660") == 0)
811 {
812 node->iso_type = 0;
813 node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
814
815 grub_file_read(file, &data, 1); // just read for hook trigger
816 node->offset = grub_iso9660_get_last_read_pos(file);
817 }
818 else
819 {
820 /* TBD */
821 }
822
823 node->size = file->size;
824 g_valid_initrd_count++;
825
826 grub_file_close(file);
827 }
828
829 *filtcnt = sizefilt;
830
831 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
832 }
833
834
835 grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
836 {
837 int sizefilt = 0;
838
839 (void)ctxt;
840 (void)argc;
841 (void)args;
842
843 ventoy_linux_locate_initrd(1, &sizefilt);
844
845 if (g_valid_initrd_count == 0 && sizefilt > 0)
846 {
847 ventoy_linux_locate_initrd(0, &sizefilt);
848 }
849
850 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
851 }
852
853 grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
854 {
855 char *template_file = NULL;
856 char *template_buf = NULL;
857 grub_uint8_t *buf = NULL;
858 grub_uint32_t mod;
859 grub_uint32_t headlen;
860 grub_uint32_t initrd_head_len;
861 grub_uint32_t padlen;
862 grub_uint32_t img_chunk_size;
863 grub_uint32_t template_size = 0;
864 grub_file_t file;
865 grub_file_t scriptfile;
866
867 (void)ctxt;
868 (void)argc;
869
870 if (argc != 3)
871 {
872 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name);
873 }
874
875 if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0)
876 {
877 return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n");
878 }
879
880 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
881
882 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
883 if (!file)
884 {
885 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
886 }
887
888 if (g_ventoy_cpio_buf)
889 {
890 grub_free(g_ventoy_cpio_buf);
891 g_ventoy_cpio_buf = NULL;
892 g_ventoy_cpio_size = 0;
893 }
894
895 template_file = ventoy_plugin_get_install_template(args[1]);
896 if (template_file)
897 {
898 debug("auto install template: <%s>\n", template_file);
899 scriptfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], template_file);
900 if (scriptfile)
901 {
902 debug("auto install script size %d\n", (int)scriptfile->size);
903 template_size = scriptfile->size;
904 template_buf = grub_malloc(template_size);
905 if (template_buf)
906 {
907 grub_file_read(scriptfile, template_buf, template_size);
908 }
909
910 grub_file_close(scriptfile);
911 }
912 else
913 {
914 debug("Failed to open install script %s%s\n", args[2], template_file);
915 }
916 }
917
918 g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + img_chunk_size);
919 if (NULL == g_ventoy_cpio_buf)
920 {
921 grub_file_close(file);
922 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size + 4096 + img_chunk_size);
923 }
924
925 grub_file_read(file, g_ventoy_cpio_buf, file->size);
926
927 buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4);
928 while (*((grub_uint32_t *)buf) != 0x37303730)
929 {
930 buf -= 4;
931 }
932
933 /* get initrd head len */
934 initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx");
935
936 /* step1: insert image chunk data to cpio */
937 headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map");
938 buf += headlen + ventoy_align(img_chunk_size, 4);
939
940 if (template_buf)
941 {
942 headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall");
943 buf += headlen + ventoy_align(template_size, 4);
944 }
945
946 /* step2: insert os param to cpio */
947 headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
948 padlen = sizeof(ventoy_os_param);
949 g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len;
950 mod = g_ventoy_cpio_size % 2048;
951 if (mod)
952 {
953 g_ventoy_cpio_size += 2048 - mod;
954 padlen += 2048 - mod;
955 }
956
957 /* update os param data size, the data will be updated before chain boot */
958 ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8);
959 g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen;
960
961 /* step3: fill initrd cpio head, the file size will be updated before chain boot */
962 g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen);
963 ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx");
964
965 grub_file_close(file);
966
967 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
968 }
969
970
971 grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
972 {
973 int ventoy_compatible = 0;
974 grub_uint32_t size = 0;
975 grub_uint64_t isosize = 0;
976 grub_uint32_t boot_catlog = 0;
977 grub_uint32_t img_chunk_size = 0;
978 grub_uint32_t override_size = 0;
979 grub_uint32_t virt_chunk_size = 0;
980 grub_file_t file;
981 grub_disk_t disk;
982 const char *pLastChain = NULL;
983 const char *compatible;
984 ventoy_chain_head *chain;
985 char envbuf[64];
986
987 (void)ctxt;
988 (void)argc;
989
990 compatible = grub_env_get("ventoy_compatible");
991 if (compatible && compatible[0] == 'Y')
992 {
993 ventoy_compatible = 1;
994 }
995
996 if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL))
997 {
998 grub_printf("ventoy not ready\n");
999 return 1;
1000 }
1001
1002 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1003 if (!file)
1004 {
1005 return 1;
1006 }
1007
1008 isosize = file->size;
1009
1010 boot_catlog = ventoy_get_iso_boot_catlog(file);
1011 if (boot_catlog)
1012 {
1013 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1014 {
1015 grub_env_set("LoadIsoEfiDriver", "on");
1016 }
1017 }
1018 else
1019 {
1020 if (ventoy_is_efi_os())
1021 {
1022 grub_env_set("LoadIsoEfiDriver", "on");
1023 }
1024 else
1025 {
1026 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1027 }
1028 }
1029
1030 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1031
1032 if (ventoy_compatible)
1033 {
1034 size = sizeof(ventoy_chain_head) + img_chunk_size;
1035 }
1036 else
1037 {
1038 override_size = ventoy_linux_get_override_chunk_size();
1039 virt_chunk_size = ventoy_linux_get_virt_chunk_size();
1040 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1041 }
1042
1043 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1044 if (pLastChain)
1045 {
1046 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1047 if (chain)
1048 {
1049 debug("free last chain memory %p\n", chain);
1050 grub_free(chain);
1051 }
1052 }
1053
1054 chain = grub_malloc(size);
1055 if (!chain)
1056 {
1057 grub_printf("Failed to alloc chain memory size %u\n", size);
1058 grub_file_close(file);
1059 return 1;
1060 }
1061
1062 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1063 grub_env_set("vtoy_chain_mem_addr", envbuf);
1064 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1065 grub_env_set("vtoy_chain_mem_size", envbuf);
1066
1067 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1068
1069 /* part 1: os parameter */
1070 ventoy_fill_os_param(file, &(chain->os_param));
1071
1072 /* part 2: chain head */
1073 disk = file->device->disk;
1074 chain->disk_drive = disk->id;
1075 chain->disk_sector_size = (1 << disk->log_sector_size);
1076 chain->real_img_size_in_bytes = file->size;
1077 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1078 chain->boot_catalog = boot_catlog;
1079
1080 if (!ventoy_is_efi_os())
1081 {
1082 grub_file_seek(file, boot_catlog * 2048);
1083 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1084 }
1085
1086 /* part 3: image chunk */
1087 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1088 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1089 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1090
1091 if (ventoy_compatible)
1092 {
1093 return 0;
1094 }
1095
1096 if (g_valid_initrd_count == 0)
1097 {
1098 return 0;
1099 }
1100
1101 /* part 4: override chunk */
1102 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1103 chain->override_chunk_num = g_valid_initrd_count;
1104 ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
1105
1106 /* part 5: virt chunk */
1107 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1108 chain->virt_chunk_num = g_valid_initrd_count;
1109 ventoy_linux_fill_virt_data(isosize, chain);
1110
1111 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1112 }
1113