]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c
179739b2a41f53464fad8e7eb2043809472fe3ac
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_unix.c
1 /******************************************************************************
2 * ventoy_unix.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/elf.h>
37 #include <grub/elfload.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
40
41 GRUB_MOD_LICENSE ("GPLv3+");
42
43 char g_ko_mod_path[256];
44 int g_conf_new_len = 0;
45 char *g_conf_new_data = NULL;
46
47 int g_mod_new_len = 0;
48 char *g_mod_new_data = NULL;
49
50 grub_uint64_t g_mod_override_offset = 0;
51 grub_uint64_t g_conf_override_offset = 0;
52
53 static int ventoy_get_file_override(const char *filename, grub_uint64_t *offset)
54 {
55 grub_file_t file;
56
57 *offset = 0;
58
59 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", filename);
60 if (!file)
61 {
62 return 1;
63 }
64
65 *offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
66
67 grub_file_close(file);
68
69 return 0;
70 }
71
72 static grub_uint32_t ventoy_unix_get_override_chunk_count(void)
73 {
74 grub_uint32_t count = 0;
75
76 if (g_conf_new_len > 0)
77 {
78 count++;
79 }
80
81 if (g_mod_new_len > 0)
82 {
83 count++;
84 }
85
86 return count;
87 }
88
89 static grub_uint32_t ventoy_unix_get_virt_chunk_count(void)
90 {
91 grub_uint32_t count = 0;
92
93 if (g_conf_new_len > 0)
94 {
95 count++;
96 }
97
98 if (g_mod_new_len > 0)
99 {
100 count++;
101 }
102
103 return count;
104 }
105 static grub_uint32_t ventoy_unix_get_virt_chunk_size(void)
106 {
107 grub_uint32_t size;
108
109 size = sizeof(ventoy_virt_chunk) * ventoy_unix_get_virt_chunk_count();
110
111 if (g_conf_new_len > 0)
112 {
113 size += ventoy_align_2k(g_conf_new_len);
114 }
115
116 if (g_mod_new_len > 0)
117 {
118 size += ventoy_align_2k(g_mod_new_len);
119 }
120
121 return size;
122 }
123
124 static void ventoy_unix_fill_override_data( grub_uint64_t isosize, void *override)
125 {
126 grub_uint64_t sector;
127 ventoy_override_chunk *cur;
128 ventoy_iso9660_override *dirent;
129
130 sector = (isosize + 2047) / 2048;
131
132 cur = (ventoy_override_chunk *)override;
133
134 if (g_conf_new_len > 0)
135 {
136 /* loader.conf */
137 cur->img_offset = g_conf_override_offset;
138 cur->override_size = sizeof(ventoy_iso9660_override);
139 dirent = (ventoy_iso9660_override *)cur->override_data;
140 dirent->first_sector = (grub_uint32_t)sector;
141 dirent->size = (grub_uint32_t)g_conf_new_len;
142 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
143 dirent->size_be = grub_swap_bytes32(dirent->size);
144 sector += (dirent->size + 2047) / 2048;
145 }
146
147 if (g_mod_new_len > 0)
148 {
149 /* mod.ko */
150 cur++;
151 cur->img_offset = g_mod_override_offset;
152 cur->override_size = sizeof(ventoy_iso9660_override);
153 dirent = (ventoy_iso9660_override *)cur->override_data;
154 dirent->first_sector = (grub_uint32_t)sector;
155 dirent->size = (grub_uint32_t)g_mod_new_len;
156 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
157 dirent->size_be = grub_swap_bytes32(dirent->size);
158 sector += (dirent->size + 2047) / 2048;
159 }
160
161 return;
162 }
163
164 static void ventoy_unix_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
165 {
166 grub_uint64_t sector;
167 grub_uint32_t offset;
168 grub_uint32_t data_secs;
169 char *override;
170 ventoy_virt_chunk *cur;
171
172 override = (char *)chain + chain->virt_chunk_offset;
173 cur = (ventoy_virt_chunk *)override;
174
175 sector = (isosize + 2047) / 2048;
176 offset = 2 * sizeof(ventoy_virt_chunk);
177
178 if (g_conf_new_len > 0)
179 {
180 ventoy_unix_fill_virt(g_conf_new_data, g_conf_new_len);
181 }
182
183 if (g_mod_new_len > 0)
184 {
185 ventoy_unix_fill_virt(g_mod_new_data, g_mod_new_len);
186 }
187
188 return;
189 }
190
191 static int ventoy_freebsd_append_conf(char *buf, const char *isopath)
192 {
193 int pos = 0;
194 grub_uint32_t i;
195 grub_disk_t disk;
196 grub_file_t isofile;
197 char uuid[64] = {0};
198 ventoy_img_chunk *chunk;
199 grub_uint8_t disk_sig[4];
200 grub_uint8_t disk_guid[16];
201
202 debug("ventoy_freebsd_append_conf %s\n", isopath);
203
204 isofile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", isopath);
205 if (!isofile)
206 {
207 return 1;
208 }
209
210 vtoy_ssprintf(buf, pos, "ventoy_load=\"%s\"\n", "YES");
211 vtoy_ssprintf(buf, pos, "ventoy_name=\"%s\"\n", g_ko_mod_path);
212
213 disk = isofile->device->disk;
214
215 ventoy_get_disk_guid(isofile->name, disk_guid, disk_sig);
216
217 for (i = 0; i < 16; i++)
218 {
219 grub_snprintf(uuid + i * 2, sizeof(uuid), "%02x", disk_guid[i]);
220 }
221
222 vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksize=%llu\n", (ulonglong)(disk->total_sectors * (1 << disk->log_sector_size)));
223 vtoy_ssprintf(buf, pos, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid);
224 vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksignature=%02x%02x%02x%02x\n", disk_sig[0], disk_sig[1], disk_sig[2], disk_sig[3]);
225 vtoy_ssprintf(buf, pos, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list.cur_chunk);
226
227 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
228 {
229 chunk = g_img_chunk_list.chunk + i;
230 vtoy_ssprintf(buf, pos, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n",
231 i, (ulonglong)(chunk->disk_start_sector * 512),
232 (ulonglong)((chunk->disk_end_sector + 1) * 512));
233 }
234
235 grub_file_close(isofile);
236
237 return pos;
238 }
239
240 static int ventoy_dragonfly_append_conf(char *buf, const char *isopath)
241 {
242 int pos = 0;
243
244 debug("ventoy_dragonfly_append_conf %s\n", isopath);
245
246 vtoy_ssprintf(buf, pos, "tmpfs_load=\"%s\"\n", "YES");
247 vtoy_ssprintf(buf, pos, "dm_target_linear_load=\"%s\"\n", "YES");
248 vtoy_ssprintf(buf, pos, "initrd.img_load=\"%s\"\n", "YES");
249 vtoy_ssprintf(buf, pos, "initrd.img_type=\"%s\"\n", "md_image");
250 vtoy_ssprintf(buf, pos, "vfs.root.mountfrom=\"%s\"\n", "ufs:md0s0");
251
252 return pos;
253 }
254
255 grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args)
256 {
257 (void)ctxt;
258 (void)argc;
259 (void)args;
260
261 g_conf_new_len = 0;
262 g_mod_new_len = 0;
263 g_mod_override_offset = 0;
264 g_conf_override_offset = 0;
265
266 check_free(g_mod_new_data, grub_free);
267 check_free(g_conf_new_data, grub_free);
268
269 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
270 }
271
272 grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args)
273 {
274 grub_file_t file;
275 const char *ver = NULL;
276 char *buf = NULL;
277 VTOY_JSON *json = NULL;
278
279 (void)ctxt;
280 (void)argc;
281
282 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
283 if (!file)
284 {
285 debug("Failed to open file %s\n", args[0]);
286 return 1;
287 }
288
289 buf = grub_malloc(file->size + 2);
290 if (!buf)
291 {
292 grub_file_close(file);
293 return 0;
294 }
295 grub_file_read(file, buf, file->size);
296 buf[file->size] = 0;
297
298 json = vtoy_json_create();
299 if (!json)
300 {
301 goto end;
302 }
303
304 if (vtoy_json_parse(json, buf))
305 {
306 goto end;
307 }
308
309 ver = vtoy_json_get_string_ex(json->pstChild, "Version");
310 if (ver)
311 {
312 debug("freenas version:<%s>\n", ver);
313 ventoy_set_env(args[1], ver);
314 }
315 else
316 {
317 debug("freenas version:<%s>\n", "NOT FOUND");
318 grub_env_unset(args[1]);
319 }
320
321 end:
322 grub_check_free(buf);
323 check_free(json, vtoy_json_destroy);
324 grub_file_close(file);
325
326 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
327 }
328
329 grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args)
330 {
331 grub_file_t file;
332 char *buf;
333 char *start = NULL;
334 char *nextline = NULL;
335
336 (void)ctxt;
337 (void)argc;
338 (void)args;
339
340 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
341 if (!file)
342 {
343 debug("Failed to open file %s\n", args[0]);
344 return 1;
345 }
346
347 buf = grub_zalloc(file->size + 2);
348 if (!buf)
349 {
350 grub_file_close(file);
351 return 0;
352 }
353 grub_file_read(file, buf, file->size);
354
355 for (start = buf; start; start = nextline)
356 {
357 if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0)
358 {
359 nextline = start;
360 while (*nextline && *nextline != '\r' && *nextline != '\n')
361 {
362 nextline++;
363 }
364
365 *nextline = 0;
366 break;
367 }
368 nextline = ventoy_get_line(start);
369 }
370
371 if (start)
372 {
373 debug("freebsd version:<%s>\n", start);
374 ventoy_set_env(args[1], start);
375 }
376 else
377 {
378 debug("freebsd version:<%s>\n", "NOT FOUND");
379 grub_env_unset(args[1]);
380 }
381
382 grub_free(buf);
383 grub_file_close(file);
384
385 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
386 }
387
388 grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args)
389 {
390 int j;
391 int k;
392 grub_elf_t elf = NULL;
393 grub_off_t offset = 0;
394 grub_uint32_t len = 0;
395 char *str = NULL;
396 char *data = NULL;
397 void *hdr = NULL;
398 char ver[64] = {0};
399
400 (void)ctxt;
401 (void)argc;
402 (void)args;
403
404 if (argc != 3)
405 {
406 debug("Invalid argc %d\n", argc);
407 return 1;
408 }
409
410 data = grub_zalloc(8192);
411 if (!data)
412 {
413 goto out;
414 }
415
416 elf = grub_elf_open(args[0], GRUB_FILE_TYPE_LINUX_INITRD);
417 if (!elf)
418 {
419 debug("Failed to open file %s\n", args[0]);
420 goto out;
421 }
422
423 if (args[1][0] == '6')
424 {
425 Elf64_Ehdr *e = &(elf->ehdr.ehdr64);
426 Elf64_Shdr *h;
427 Elf64_Shdr *s;
428 Elf64_Shdr *t;
429 Elf64_Half i;
430
431 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
432 if (!h)
433 {
434 goto out;
435 }
436
437 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
438 grub_file_seek(elf->file, e->e_shoff);
439 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
440
441 s = (Elf64_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
442 str = grub_malloc(s->sh_size + 1);
443 if (!str)
444 {
445 goto out;
446 }
447 str[s->sh_size] = 0;
448
449 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
450 grub_file_seek(elf->file, s->sh_offset);
451 grub_file_read(elf->file, str, s->sh_size);
452
453 for (t = h, i = 0; i < e->e_shnum; i++)
454 {
455 if (grub_strcmp(str + t->sh_name, ".data") == 0)
456 {
457 offset = t->sh_offset;
458 len = t->sh_size;
459 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
460 break;
461 }
462 t = (Elf64_Shdr *)((char *)t + e->e_shentsize);
463 }
464 }
465 else
466 {
467 Elf32_Ehdr *e = &(elf->ehdr.ehdr32);
468 Elf32_Shdr *h;
469 Elf32_Shdr *s;
470 Elf32_Shdr *t;
471 Elf32_Half i;
472
473 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
474 if (!h)
475 {
476 goto out;
477 }
478
479 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
480 grub_file_seek(elf->file, e->e_shoff);
481 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
482
483 s = (Elf32_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
484 str = grub_malloc(s->sh_size + 1);
485 if (!str)
486 {
487 goto out;
488 }
489 str[s->sh_size] = 0;
490
491 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
492 grub_file_seek(elf->file, s->sh_offset);
493 grub_file_read(elf->file, str, s->sh_size);
494
495 for (t = h, i = 0; i < e->e_shnum; i++)
496 {
497 if (grub_strcmp(str + t->sh_name, ".data") == 0)
498 {
499 offset = t->sh_offset;
500 len = t->sh_size;
501 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
502 break;
503 }
504 t = (Elf32_Shdr *)((char *)t + e->e_shentsize);
505 }
506 }
507
508 if (offset == 0 || len == 0)
509 {
510 debug(".data section not found %s\n", args[0]);
511 goto out;
512 }
513
514 grub_file_seek(elf->file, offset + len - 8192);
515 grub_file_read(elf->file, data, 8192);
516
517 for (j = 0; j < 8192 - 12; j++)
518 {
519 if (grub_strncmp(data + j, "@(#)FreeBSD ", 12) == 0)
520 {
521 for (k = j + 12; k < 8192; k++)
522 {
523 if (0 == grub_isdigit(data[k]) && data[k] != '.')
524 {
525 data[k] = 0;
526 break;
527 }
528 }
529
530 grub_snprintf(ver, sizeof(ver), "%s", data + j + 12);
531 break;
532 }
533 }
534
535 if (ver[0])
536 {
537 k = (int)grub_strtoul(ver, NULL, 10);
538 debug("freebsd version:<%s> <%d.x>\n", ver, k);
539 grub_snprintf(ver, sizeof(ver), "%d.x", k);
540 ventoy_set_env(args[2], ver);
541 }
542 else
543 {
544 debug("freebsd version:<%s>\n", "NOT FOUND");
545 }
546
547 out:
548 grub_check_free(str);
549 grub_check_free(hdr);
550 grub_check_free(data);
551 check_free(elf, grub_elf_close);
552
553 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
554 }
555
556 grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args)
557 {
558 grub_uint32_t i;
559 char *data;
560 grub_uint64_t offset;
561 grub_file_t file;
562 const char *confile = NULL;
563 const char * loader_conf[] =
564 {
565 "/boot/loader.conf",
566 "/boot/defaults/loader.conf",
567 };
568
569 (void)ctxt;
570
571 if (argc != 2)
572 {
573 debug("Replace conf invalid argc %d\n", argc);
574 return 1;
575 }
576
577 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
578 {
579 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
580 {
581 confile = loader_conf[i];
582 g_conf_override_offset = offset;
583 break;
584 }
585 }
586
587 if (confile == NULL)
588 {
589 debug("Can't find loader.conf file from %u locations\n", i);
590 return 1;
591 }
592
593 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
594 if (!file)
595 {
596 debug("Failed to open %s \n", confile);
597 return 1;
598 }
599
600 debug("old conf file size:%d\n", (int)file->size);
601
602 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
603 if (!data)
604 {
605 grub_file_close(file);
606 return 1;
607 }
608
609 grub_file_read(file, data, file->size);
610 grub_file_close(file);
611
612 g_conf_new_data = data;
613 g_conf_new_len = (int)file->size;
614
615 if (grub_strcmp(args[0], "FreeBSD") == 0)
616 {
617 g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1]);
618 }
619 else if (grub_strcmp(args[0], "DragonFly") == 0)
620 {
621 g_conf_new_len += ventoy_dragonfly_append_conf(data + file->size, args[1]);
622 }
623
624 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
625 }
626
627 grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args)
628 {
629 char *data;
630 grub_uint64_t offset;
631 grub_file_t file;
632
633 (void)ctxt;
634
635 if (argc != 2)
636 {
637 debug("Replace ko invalid argc %d\n", argc);
638 return 1;
639 }
640
641 debug("replace ko %s\n", args[0]);
642
643 if (ventoy_get_file_override(args[0], &offset) == 0)
644 {
645 grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]);
646 g_mod_override_offset = offset;
647 }
648 else
649 {
650 debug("Can't find replace ko file from %s\n", args[0]);
651 return 1;
652 }
653
654 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]);
655 if (!file)
656 {
657 debug("Failed to open %s \n", args[1]);
658 return 1;
659 }
660
661 debug("new ko file size:%d\n", (int)file->size);
662
663 data = grub_malloc(file->size);
664 if (!data)
665 {
666 debug("Failed to alloc memory for new ko %d\n", (int)file->size);
667 grub_file_close(file);
668 return 1;
669 }
670
671 grub_file_read(file, data, file->size);
672 grub_file_close(file);
673
674 g_mod_new_data = data;
675 g_mod_new_len = (int)file->size;
676
677 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
678 }
679
680 grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args)
681 {
682 int i;
683 grub_uint8_t *byte;
684 grub_uint32_t memsize;
685 ventoy_image_desc *desc;
686 grub_uint8_t flag[32] = {
687 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
688 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
689 };
690
691 (void)ctxt;
692 (void)argc;
693 (void)args;
694
695 debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data);
696
697 if (!g_mod_new_data)
698 {
699 goto end;
700 }
701
702 byte = (grub_uint8_t *)g_mod_new_data;
703 for (i = 0; i < g_mod_new_len - 32; i += 16)
704 {
705 if (byte[i] == 0xFF && byte[i + 1] == 0xEE)
706 {
707 if (grub_memcmp(flag, byte + i, 32) == 0)
708 {
709 debug("Find position flag at %d(0x%x)\n", i, i);
710 break;
711 }
712 }
713 }
714
715 if (i >= g_mod_new_len - 32)
716 {
717 debug("Failed to find position flag %d\n", i);
718 goto end;
719 }
720
721 desc = (ventoy_image_desc *)(byte + i);
722 desc->disk_size = g_ventoy_disk_size;
723 desc->part1_size = g_ventoy_disk_part_size[0];
724 grub_memcpy(desc->disk_uuid, g_ventoy_part_info->MBR.BootCode + 0x180, 16);
725 grub_memcpy(desc->disk_signature, g_ventoy_part_info->MBR.BootCode + 0x1B8, 4);
726
727 desc->img_chunk_count = g_img_chunk_list.cur_chunk;
728 memsize = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
729
730 debug("image chunk count:%u memsize:%u\n", desc->img_chunk_count, memsize);
731
732 if (memsize >= VTOY_SIZE_1MB * 8)
733 {
734 grub_printf("image chunk count:%u memsize:%u too big\n", desc->img_chunk_count, memsize);
735 goto end;
736 }
737
738 grub_memcpy(desc + 1, g_img_chunk_list.chunk, memsize);
739
740 end:
741 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
742 }
743
744 grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args)
745 {
746 int newlen;
747 grub_uint8_t *buf;
748
749 (void)ctxt;
750 (void)argc;
751 (void)args;
752
753 debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data);
754
755 if (!g_mod_new_data)
756 {
757 goto end;
758 }
759
760 buf = grub_malloc(g_mod_new_len);
761 if (!buf)
762 {
763 goto end;
764 }
765
766 newlen = ventoy_gzip_compress(g_mod_new_data, g_mod_new_len, buf, g_mod_new_len);
767
768 grub_free(g_mod_new_data);
769
770 debug("gzip org len:%d newlen:%d\n", g_mod_new_len, newlen);
771
772 g_mod_new_data = (char *)buf;
773 g_mod_new_len = newlen;
774
775 end:
776 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
777 }
778
779 grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
780 {
781 int ventoy_compatible = 0;
782 grub_uint32_t size = 0;
783 grub_uint64_t isosize = 0;
784 grub_uint32_t boot_catlog = 0;
785 grub_uint32_t img_chunk_size = 0;
786 grub_uint32_t override_count = 0;
787 grub_uint32_t override_size = 0;
788 grub_uint32_t virt_chunk_size = 0;
789 grub_file_t file;
790 grub_disk_t disk;
791 const char *pLastChain = NULL;
792 const char *compatible;
793 ventoy_chain_head *chain;
794 char envbuf[64];
795
796 (void)ctxt;
797 (void)argc;
798
799 compatible = grub_env_get("ventoy_compatible");
800 if (compatible && compatible[0] == 'Y')
801 {
802 ventoy_compatible = 1;
803 }
804
805 if (NULL == g_img_chunk_list.chunk)
806 {
807 grub_printf("ventoy not ready\n");
808 return 1;
809 }
810
811 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
812 if (!file)
813 {
814 return 1;
815 }
816
817 isosize = file->size;
818
819 boot_catlog = ventoy_get_iso_boot_catlog(file);
820 if (boot_catlog)
821 {
822 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
823 {
824 grub_env_set("LoadIsoEfiDriver", "on");
825 }
826 }
827 else
828 {
829 if (ventoy_is_efi_os())
830 {
831 grub_env_set("LoadIsoEfiDriver", "on");
832 }
833 else
834 {
835 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
836 }
837 }
838
839 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
840
841 if (ventoy_compatible)
842 {
843 size = sizeof(ventoy_chain_head) + img_chunk_size;
844 }
845 else
846 {
847 override_count = ventoy_unix_get_override_chunk_count();
848 override_size = override_count * sizeof(ventoy_override_chunk);
849
850 virt_chunk_size = ventoy_unix_get_virt_chunk_size();
851 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
852 }
853
854 pLastChain = grub_env_get("vtoy_chain_mem_addr");
855 if (pLastChain)
856 {
857 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
858 if (chain)
859 {
860 debug("free last chain memory %p\n", chain);
861 grub_free(chain);
862 }
863 }
864
865 chain = grub_malloc(size);
866 if (!chain)
867 {
868 grub_printf("Failed to alloc chain memory size %u\n", size);
869 grub_file_close(file);
870 return 1;
871 }
872
873 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
874 grub_env_set("vtoy_chain_mem_addr", envbuf);
875 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
876 grub_env_set("vtoy_chain_mem_size", envbuf);
877
878 grub_memset(chain, 0, sizeof(ventoy_chain_head));
879
880 /* part 1: os parameter */
881 g_ventoy_chain_type = ventoy_chain_linux;
882 ventoy_fill_os_param(file, &(chain->os_param));
883
884 /* part 2: chain head */
885 disk = file->device->disk;
886 chain->disk_drive = disk->id;
887 chain->disk_sector_size = (1 << disk->log_sector_size);
888 chain->real_img_size_in_bytes = file->size;
889 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
890 chain->boot_catalog = boot_catlog;
891
892 if (!ventoy_is_efi_os())
893 {
894 grub_file_seek(file, boot_catlog * 2048);
895 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
896 }
897
898 /* part 3: image chunk */
899 chain->img_chunk_offset = sizeof(ventoy_chain_head);
900 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
901 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
902
903 if (ventoy_compatible)
904 {
905 return 0;
906 }
907
908 /* part 4: override chunk */
909 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
910 chain->override_chunk_num = override_count;
911 ventoy_unix_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
912
913 /* part 5: virt chunk */
914 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
915 chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count();
916 ventoy_unix_fill_virt_data(isosize, chain);
917
918 grub_file_close(file);
919
920 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
921 }
922