]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c
8ff212488fb68b1799d78db78edf98d7fae65f03
[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 int g_mod_search_magic = 0;
51 int g_unix_vlnk_boot = 0;
52
53 int g_ko_fillmap_len = 0;
54 char *g_ko_fillmap_data = NULL;
55
56 grub_uint64_t g_mod_override_offset = 0;
57 grub_uint64_t g_conf_override_offset = 0;
58
59 static int ventoy_get_file_override(const char *filename, grub_uint64_t *offset)
60 {
61 grub_file_t file;
62
63 *offset = 0;
64
65 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", filename);
66 if (!file)
67 {
68 return 1;
69 }
70
71 *offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
72
73 grub_file_close(file);
74
75 return 0;
76 }
77
78 static grub_uint32_t ventoy_unix_get_override_chunk_count(void)
79 {
80 grub_uint32_t count = 0;
81
82 if (g_conf_new_len > 0)
83 {
84 count++;
85 }
86
87 if (g_mod_new_len > 0)
88 {
89 count++;
90 }
91
92 if (g_ko_fillmap_len > 0)
93 {
94 count += (g_ko_fillmap_len / 512);
95 if ((g_ko_fillmap_len % 512) > 0)
96 {
97 count++;
98 }
99 }
100
101 return count;
102 }
103
104 static grub_uint32_t ventoy_unix_get_virt_chunk_count(void)
105 {
106 grub_uint32_t count = 0;
107
108 if (g_conf_new_len > 0)
109 {
110 count++;
111 }
112
113 if (g_mod_new_len > 0)
114 {
115 count++;
116 }
117
118 return count;
119 }
120 static grub_uint32_t ventoy_unix_get_virt_chunk_size(void)
121 {
122 grub_uint32_t size;
123
124 size = sizeof(ventoy_virt_chunk) * ventoy_unix_get_virt_chunk_count();
125
126 if (g_conf_new_len > 0)
127 {
128 size += ventoy_align_2k(g_conf_new_len);
129 }
130
131 if (g_mod_new_len > 0)
132 {
133 size += ventoy_align_2k(g_mod_new_len);
134 }
135
136 return size;
137 }
138
139 static void ventoy_unix_fill_map_data(ventoy_chain_head *chain, struct g_ventoy_map *map)
140 {
141 grub_uint32_t i;
142 ventoy_img_chunk *chunk = NULL;
143
144 debug("Fill unix map data: <%llu> <%u> %p\n",
145 (unsigned long long)chain->os_param.vtoy_disk_size, g_img_chunk_list.cur_chunk, map);
146
147 map->magic1[0] = map->magic2[0] = VENTOY_UNIX_SEG_MAGIC0;
148 map->magic1[1] = map->magic2[1] = VENTOY_UNIX_SEG_MAGIC1;
149 map->magic1[2] = map->magic2[2] = VENTOY_UNIX_SEG_MAGIC2;
150 map->magic1[3] = map->magic2[3] = VENTOY_UNIX_SEG_MAGIC3;
151
152 map->disksize = chain->os_param.vtoy_disk_size;
153 grub_memcpy(map->diskuuid, chain->os_param.vtoy_disk_guid, 16);
154
155 map->segnum = g_img_chunk_list.cur_chunk;
156 if (g_img_chunk_list.cur_chunk > VENTOY_UNIX_MAX_SEGNUM)
157 {
158 debug("####[FAIL] Too many segments for the ISO file %u\n", g_img_chunk_list.cur_chunk);
159 map->segnum = VENTOY_UNIX_MAX_SEGNUM;
160 }
161
162 for (i = 0; i < (grub_uint32_t)(map->segnum); i++)
163 {
164 chunk = g_img_chunk_list.chunk + i;
165 map->seglist[i].seg_start_bytes = chunk->disk_start_sector * 512ULL;
166 map->seglist[i].seg_end_bytes = (chunk->disk_end_sector + 1) * 512ULL;
167 }
168 }
169
170 static void ventoy_unix_fill_override_data( grub_uint64_t isosize, ventoy_chain_head *chain)
171 {
172 int i;
173 int left;
174 char *data = NULL;
175 grub_uint64_t offset;
176 grub_uint64_t sector;
177 ventoy_override_chunk *cur;
178 ventoy_iso9660_override *dirent;
179
180 sector = (isosize + 2047) / 2048;
181
182 cur = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
183
184 if (g_conf_new_len > 0)
185 {
186 /* loader.conf */
187 cur->img_offset = g_conf_override_offset;
188 cur->override_size = sizeof(ventoy_iso9660_override);
189 dirent = (ventoy_iso9660_override *)cur->override_data;
190 dirent->first_sector = (grub_uint32_t)sector;
191 dirent->size = (grub_uint32_t)g_conf_new_len;
192 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
193 dirent->size_be = grub_swap_bytes32(dirent->size);
194 sector += (dirent->size + 2047) / 2048;
195 cur++;
196 }
197
198 if (g_mod_new_len > 0)
199 {
200 /* mod.ko */
201 cur->img_offset = g_mod_override_offset;
202 cur->override_size = sizeof(ventoy_iso9660_override);
203 dirent = (ventoy_iso9660_override *)cur->override_data;
204 dirent->first_sector = (grub_uint32_t)sector;
205 dirent->size = (grub_uint32_t)g_mod_new_len;
206 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
207 dirent->size_be = grub_swap_bytes32(dirent->size);
208 sector += (dirent->size + 2047) / 2048;
209 cur++;
210 }
211
212 if (g_ko_fillmap_len > 0)
213 {
214 data = g_ko_fillmap_data;
215 offset = g_mod_override_offset;
216
217 ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)data);
218
219 for (i = 0; i < g_ko_fillmap_len / 512; i++)
220 {
221 cur->img_offset = offset;
222 cur->override_size = 512;
223 grub_memcpy(cur->override_data, data, 512);
224
225 offset += 512;
226 data += 512;
227 cur++;
228 }
229
230 left = (g_ko_fillmap_len % 512);
231 if (left > 0)
232 {
233 cur->img_offset = offset;
234 cur->override_size = left;
235 grub_memcpy(cur->override_data, data, left);
236
237 offset += left;
238 cur++;
239 }
240 }
241
242 return;
243 }
244
245 static void ventoy_unix_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
246 {
247 grub_uint64_t sector;
248 grub_uint32_t offset;
249 grub_uint32_t data_secs;
250 char *override;
251 ventoy_virt_chunk *cur;
252
253 override = (char *)chain + chain->virt_chunk_offset;
254 cur = (ventoy_virt_chunk *)override;
255
256 sector = (isosize + 2047) / 2048;
257 offset = 2 * sizeof(ventoy_virt_chunk);
258
259 if (g_conf_new_len > 0)
260 {
261 ventoy_unix_fill_virt(g_conf_new_data, g_conf_new_len);
262 }
263
264 if (g_mod_new_len > 0)
265 {
266 if (g_mod_search_magic > 0)
267 {
268 ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)(g_mod_new_data + g_mod_search_magic));
269 }
270
271 ventoy_unix_fill_virt(g_mod_new_data, g_mod_new_len);
272 }
273
274 return;
275 }
276
277 static int ventoy_freebsd_append_conf(char *buf, const char *isopath, const char *alias)
278 {
279 int pos = 0;
280 grub_uint32_t i;
281 grub_disk_t disk;
282 grub_file_t isofile;
283 char uuid[64] = {0};
284 const char *val = NULL;
285 ventoy_img_chunk *chunk;
286 grub_uint8_t disk_sig[4];
287 grub_uint8_t disk_guid[16];
288
289 debug("ventoy_freebsd_append_conf %s\n", isopath);
290
291 isofile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", isopath);
292 if (!isofile)
293 {
294 return 1;
295 }
296
297 vtoy_ssprintf(buf, pos, "ventoy_load=\"%s\"\n", "YES");
298 vtoy_ssprintf(buf, pos, "ventoy_name=\"%s\"\n", g_ko_mod_path);
299
300 if (alias)
301 {
302 vtoy_ssprintf(buf, pos, "hint.ventoy.0.alias=\"%s\"\n", alias);
303 }
304
305 if (g_unix_vlnk_boot)
306 {
307 vtoy_ssprintf(buf, pos, "hint.ventoy.0.vlnk=%d\n", 1);
308 }
309
310 val = ventoy_get_env("VTOY_UNIX_REMOUNT");
311 if (val && val[0] == '1' && val[1] == 0)
312 {
313 vtoy_ssprintf(buf, pos, "hint.ventoy.0.remount=%d\n", 1);
314 }
315
316 if (g_mod_search_magic)
317 {
318 debug("hint.ventoy NO need\n");
319 goto out;
320 }
321
322 debug("Fill hint.ventoy info\n");
323
324 disk = isofile->device->disk;
325
326 ventoy_get_disk_guid(isofile->name, disk_guid, disk_sig);
327
328 for (i = 0; i < 16; i++)
329 {
330 grub_snprintf(uuid + i * 2, sizeof(uuid), "%02x", disk_guid[i]);
331 }
332
333 vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksize=%llu\n", (ulonglong)(disk->total_sectors * (1 << disk->log_sector_size)));
334 vtoy_ssprintf(buf, pos, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid);
335 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]);
336 vtoy_ssprintf(buf, pos, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list.cur_chunk);
337
338 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
339 {
340 chunk = g_img_chunk_list.chunk + i;
341 vtoy_ssprintf(buf, pos, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n",
342 i, (ulonglong)(chunk->disk_start_sector * 512),
343 (ulonglong)((chunk->disk_end_sector + 1) * 512));
344 }
345
346 out:
347 grub_file_close(isofile);
348 return pos;
349 }
350
351 static int ventoy_dragonfly_append_conf(char *buf, const char *isopath)
352 {
353 int pos = 0;
354
355 debug("ventoy_dragonfly_append_conf %s\n", isopath);
356
357 vtoy_ssprintf(buf, pos, "tmpfs_load=\"%s\"\n", "YES");
358 vtoy_ssprintf(buf, pos, "dm_target_linear_load=\"%s\"\n", "YES");
359 vtoy_ssprintf(buf, pos, "initrd.img_load=\"%s\"\n", "YES");
360 vtoy_ssprintf(buf, pos, "initrd.img_type=\"%s\"\n", "md_image");
361 vtoy_ssprintf(buf, pos, "vfs.root.mountfrom=\"%s\"\n", "ufs:md0s0");
362
363 return pos;
364 }
365
366 grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args)
367 {
368 (void)ctxt;
369 (void)argc;
370 (void)args;
371
372 g_unix_vlnk_boot = 0;
373 g_mod_search_magic = 0;
374 g_conf_new_len = 0;
375 g_mod_new_len = 0;
376 g_mod_override_offset = 0;
377 g_conf_override_offset = 0;
378 g_ko_fillmap_len = 0;
379
380 check_free(g_mod_new_data, grub_free);
381 check_free(g_conf_new_data, grub_free);
382 check_free(g_ko_fillmap_data, grub_free);
383
384 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
385 }
386
387 grub_err_t ventoy_cmd_unix_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args)
388 {
389 grub_file_t file;
390
391 (void)ctxt;
392
393 if (argc != 1)
394 {
395 return 1;
396 }
397
398 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
399 if (file)
400 {
401 g_unix_vlnk_boot = file->vlnk;
402 grub_file_close(file);
403 }
404
405 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
406 }
407
408 grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args)
409 {
410 grub_file_t file;
411 const char *ver = NULL;
412 char *buf = NULL;
413 VTOY_JSON *json = NULL;
414
415 (void)ctxt;
416 (void)argc;
417
418 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
419 if (!file)
420 {
421 debug("Failed to open file %s\n", args[0]);
422 return 1;
423 }
424
425 buf = grub_malloc(file->size + 2);
426 if (!buf)
427 {
428 grub_file_close(file);
429 return 0;
430 }
431 grub_file_read(file, buf, file->size);
432 buf[file->size] = 0;
433
434 json = vtoy_json_create();
435 if (!json)
436 {
437 goto end;
438 }
439
440 if (vtoy_json_parse(json, buf))
441 {
442 goto end;
443 }
444
445 ver = vtoy_json_get_string_ex(json->pstChild, "Version");
446 if (ver)
447 {
448 debug("freenas version:<%s>\n", ver);
449 ventoy_set_env(args[1], ver);
450 }
451 else
452 {
453 debug("freenas version:<%s>\n", "NOT FOUND");
454 grub_env_unset(args[1]);
455 }
456
457 end:
458 grub_check_free(buf);
459 check_free(json, vtoy_json_destroy);
460 grub_file_close(file);
461
462 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
463 }
464
465 grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args)
466 {
467 grub_file_t file;
468 char *buf;
469 char *start = NULL;
470 char *nextline = NULL;
471
472 (void)ctxt;
473 (void)argc;
474 (void)args;
475
476 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
477 if (!file)
478 {
479 debug("Failed to open file %s\n", args[0]);
480 return 1;
481 }
482
483 buf = grub_zalloc(file->size + 2);
484 if (!buf)
485 {
486 grub_file_close(file);
487 return 0;
488 }
489 grub_file_read(file, buf, file->size);
490
491 for (start = buf; start; start = nextline)
492 {
493 if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0)
494 {
495 nextline = start;
496 while (*nextline && *nextline != '\r' && *nextline != '\n')
497 {
498 nextline++;
499 }
500
501 *nextline = 0;
502 break;
503 }
504 nextline = ventoy_get_line(start);
505 }
506
507 if (start)
508 {
509 debug("freebsd version:<%s>\n", start);
510 ventoy_set_env(args[1], start);
511 }
512 else
513 {
514 debug("freebsd version:<%s>\n", "NOT FOUND");
515 grub_env_unset(args[1]);
516 }
517
518 grub_free(buf);
519 grub_file_close(file);
520
521 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
522 }
523
524 grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args)
525 {
526 int j;
527 int k;
528 grub_elf_t elf = NULL;
529 grub_off_t offset = 0;
530 grub_uint32_t len = 0;
531 char *str = NULL;
532 char *data = NULL;
533 void *hdr = NULL;
534 char ver[64] = {0};
535
536 (void)ctxt;
537 (void)argc;
538 (void)args;
539
540 if (argc != 3)
541 {
542 debug("Invalid argc %d\n", argc);
543 return 1;
544 }
545
546 data = grub_zalloc(8192);
547 if (!data)
548 {
549 goto out;
550 }
551
552 elf = grub_elf_open(args[0], GRUB_FILE_TYPE_LINUX_INITRD);
553 if (!elf)
554 {
555 debug("Failed to open file %s\n", args[0]);
556 goto out;
557 }
558
559 if (args[1][0] == '6')
560 {
561 Elf64_Ehdr *e = &(elf->ehdr.ehdr64);
562 Elf64_Shdr *h;
563 Elf64_Shdr *s;
564 Elf64_Shdr *t;
565 Elf64_Half i;
566
567 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
568 if (!h)
569 {
570 goto out;
571 }
572
573 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
574 grub_file_seek(elf->file, e->e_shoff);
575 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
576
577 s = (Elf64_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
578 str = grub_malloc(s->sh_size + 1);
579 if (!str)
580 {
581 goto out;
582 }
583 str[s->sh_size] = 0;
584
585 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
586 grub_file_seek(elf->file, s->sh_offset);
587 grub_file_read(elf->file, str, s->sh_size);
588
589 for (t = h, i = 0; i < e->e_shnum; i++)
590 {
591 if (grub_strcmp(str + t->sh_name, ".data") == 0)
592 {
593 offset = t->sh_offset;
594 len = t->sh_size;
595 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
596 break;
597 }
598 t = (Elf64_Shdr *)((char *)t + e->e_shentsize);
599 }
600 }
601 else
602 {
603 Elf32_Ehdr *e = &(elf->ehdr.ehdr32);
604 Elf32_Shdr *h;
605 Elf32_Shdr *s;
606 Elf32_Shdr *t;
607 Elf32_Half i;
608
609 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
610 if (!h)
611 {
612 goto out;
613 }
614
615 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
616 grub_file_seek(elf->file, e->e_shoff);
617 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
618
619 s = (Elf32_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
620 str = grub_malloc(s->sh_size + 1);
621 if (!str)
622 {
623 goto out;
624 }
625 str[s->sh_size] = 0;
626
627 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
628 grub_file_seek(elf->file, s->sh_offset);
629 grub_file_read(elf->file, str, s->sh_size);
630
631 for (t = h, i = 0; i < e->e_shnum; i++)
632 {
633 if (grub_strcmp(str + t->sh_name, ".data") == 0)
634 {
635 offset = t->sh_offset;
636 len = t->sh_size;
637 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
638 break;
639 }
640 t = (Elf32_Shdr *)((char *)t + e->e_shentsize);
641 }
642 }
643
644 if (offset == 0 || len == 0)
645 {
646 debug(".data section not found %s\n", args[0]);
647 goto out;
648 }
649
650 grub_file_seek(elf->file, offset + len - 8192);
651 grub_file_read(elf->file, data, 8192);
652
653 for (j = 0; j < 8192 - 12; j++)
654 {
655 if (grub_strncmp(data + j, "@(#)FreeBSD ", 12) == 0)
656 {
657 for (k = j + 12; k < 8192; k++)
658 {
659 if (0 == grub_isdigit(data[k]) && data[k] != '.')
660 {
661 data[k] = 0;
662 break;
663 }
664 }
665
666 grub_snprintf(ver, sizeof(ver), "%s", data + j + 12);
667 break;
668 }
669 }
670
671 if (ver[0])
672 {
673 k = (int)grub_strtoul(ver, NULL, 10);
674 debug("freebsd version:<%s> <%d.x>\n", ver, k);
675 grub_snprintf(ver, sizeof(ver), "%d.x", k);
676 ventoy_set_env(args[2], ver);
677 }
678 else
679 {
680 debug("freebsd version:<%s>\n", "NOT FOUND");
681 }
682
683 out:
684 grub_check_free(str);
685 grub_check_free(hdr);
686 grub_check_free(data);
687 check_free(elf, grub_elf_close);
688
689 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
690 }
691
692 grub_err_t ventoy_cmd_unix_replace_grub_conf(grub_extcmd_context_t ctxt, int argc, char **args)
693 {
694 int len = 0;
695 grub_uint32_t i;
696 char *data;
697 char *pos;
698 const char *val = NULL;
699 grub_uint64_t offset;
700 grub_file_t file;
701 char extcfg[512];
702 const char *confile = NULL;
703 const char * loader_conf[] =
704 {
705 "/boot/grub/grub.cfg",
706 };
707
708 (void)ctxt;
709
710 if (argc != 1 && argc != 2)
711 {
712 debug("Replace conf invalid argc %d\n", argc);
713 return 1;
714 }
715
716 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
717 {
718 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
719 {
720 confile = loader_conf[i];
721 g_conf_override_offset = offset;
722 break;
723 }
724 }
725
726 if (confile == NULL)
727 {
728 debug("Can't find grub.cfg file from %u locations\n", i);
729 return 1;
730 }
731
732 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
733 if (!file)
734 {
735 debug("Failed to open %s \n", confile);
736 return 1;
737 }
738
739 debug("old grub2 conf file size:%d\n", (int)file->size);
740
741 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
742 if (!data)
743 {
744 grub_file_close(file);
745 return 1;
746 }
747
748 grub_file_read(file, data, file->size);
749 grub_file_close(file);
750
751 g_conf_new_data = data;
752 g_conf_new_len = (int)file->size;
753
754 pos = grub_strstr(data, "kfreebsd /boot/kernel/kernel");
755 if (pos)
756 {
757 pos += grub_strlen("kfreebsd /boot/kernel/kernel");
758 if (grub_strncmp(pos, ".gz", 3) == 0)
759 {
760 pos += 3;
761 }
762
763 if (argc == 2)
764 {
765 vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s; set kFreeBSD.hint.ventoy.0.alias=\"%s\"", args[0], args[1]);
766 }
767 else
768 {
769 vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s", args[0]);
770 }
771
772 if (g_unix_vlnk_boot)
773 {
774 vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.vlnk=%d", 1);
775 }
776
777 val = ventoy_get_env("VTOY_UNIX_REMOUNT");
778 if (val && val[0] == '1' && val[1] == 0)
779 {
780 vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.remount=%d", 1);
781 }
782
783 grub_memmove(pos + len, pos, (int)(file->size - (pos - data)));
784 grub_memcpy(pos, extcfg, len);
785 g_conf_new_len += len;
786 }
787 else
788 {
789 debug("no kfreebsd found\n");
790 }
791
792 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
793 }
794
795 grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args)
796 {
797 grub_uint32_t i;
798 char *data;
799 grub_uint64_t offset;
800 grub_file_t file;
801 const char *confile = NULL;
802 const char * loader_conf[] =
803 {
804 "/boot/loader.conf",
805 "/boot/defaults/loader.conf",
806 };
807
808 (void)ctxt;
809
810 if (argc != 2 && argc != 3)
811 {
812 debug("Replace conf invalid argc %d\n", argc);
813 return 1;
814 }
815
816 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
817 {
818 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
819 {
820 confile = loader_conf[i];
821 g_conf_override_offset = offset;
822 break;
823 }
824 }
825
826 if (confile == NULL)
827 {
828 debug("Can't find loader.conf file from %u locations\n", i);
829 return 1;
830 }
831
832 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
833 if (!file)
834 {
835 debug("Failed to open %s \n", confile);
836 return 1;
837 }
838
839 debug("old conf file <%s> size:%d\n", confile, (int)file->size);
840
841 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
842 if (!data)
843 {
844 grub_file_close(file);
845 return 1;
846 }
847
848 grub_file_read(file, data, file->size);
849 grub_file_close(file);
850
851 g_conf_new_data = data;
852 g_conf_new_len = (int)file->size;
853
854 if (grub_strcmp(args[0], "FreeBSD") == 0)
855 {
856 g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1], (argc > 2) ? args[2] : NULL);
857 }
858 else if (grub_strcmp(args[0], "DragonFly") == 0)
859 {
860 g_conf_new_len += ventoy_dragonfly_append_conf(data + file->size, args[1]);
861 }
862
863 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
864 }
865
866 static int ventoy_unix_search_magic(char *data, int len)
867 {
868 int i;
869 grub_uint32_t *magic = NULL;
870
871 for (i = 0; i < len; i += 4096)
872 {
873 magic = (grub_uint32_t *)(data + i);
874 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
875 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
876 {
877 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 12));
878 g_mod_search_magic = i;
879 return 0;
880 }
881 }
882
883 debug("unix can not find search magic\n");
884 return 1;
885 }
886
887 grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args)
888 {
889 char *data;
890 grub_uint64_t offset;
891 grub_file_t file;
892
893 (void)ctxt;
894
895 if (argc != 2)
896 {
897 debug("Replace ko invalid argc %d\n", argc);
898 return 1;
899 }
900
901 debug("replace ko %s\n", args[0]);
902
903 if (ventoy_get_file_override(args[0], &offset) == 0)
904 {
905 grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]);
906 g_mod_override_offset = offset;
907 }
908 else
909 {
910 debug("Can't find replace ko file from %s\n", args[0]);
911 return 1;
912 }
913
914 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]);
915 if (!file)
916 {
917 debug("Failed to open %s \n", args[1]);
918 return 1;
919 }
920
921 debug("new ko file size:%d\n", (int)file->size);
922
923 data = grub_malloc(file->size);
924 if (!data)
925 {
926 debug("Failed to alloc memory for new ko %d\n", (int)file->size);
927 grub_file_close(file);
928 return 1;
929 }
930
931 grub_file_read(file, data, file->size);
932 grub_file_close(file);
933
934 g_mod_new_data = data;
935 g_mod_new_len = (int)file->size;
936
937 ventoy_unix_search_magic(g_mod_new_data, g_mod_new_len);
938
939 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
940 }
941
942 grub_err_t ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt, int argc, char **args)
943 {
944 int i;
945 grub_file_t file;
946 grub_uint32_t magic[4];
947 grub_uint32_t len;
948
949 (void)ctxt;
950
951 if (argc != 1)
952 {
953 debug("Fillmap ko invalid argc %d\n", argc);
954 return 1;
955 }
956
957 debug("Fillmap ko %s\n", args[0]);
958
959 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", args[0]);
960 if (file)
961 {
962 grub_file_read(file, magic, 4); /* read for trigger */
963 g_mod_override_offset = grub_iso9660_get_last_read_pos(file);
964 }
965 else
966 {
967 debug("Can't find replace ko file from %s\n", args[0]);
968 return 1;
969 }
970
971 for (i = 0; i < (int)(file->size); i += 65536)
972 {
973 magic[0] = 0;
974 grub_file_seek(file, i);
975 grub_file_read(file, magic, sizeof(magic));
976
977 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
978 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
979 {
980 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 16));
981 g_mod_override_offset += i;
982 break;
983 }
984 }
985
986 len = (grub_uint32_t)OFFSET_OF(struct g_ventoy_map, seglist) +
987 (sizeof(struct g_ventoy_seg) * g_img_chunk_list.cur_chunk);
988
989 g_ko_fillmap_len = (int)len;
990 g_ko_fillmap_data = grub_malloc(len);
991 if (!g_ko_fillmap_data)
992 {
993 g_ko_fillmap_len = 0;
994 debug("Failed to malloc fillmap data\n");
995 }
996
997 debug("Fillmap ko segnum:%u, override len:%u data:%p\n", g_img_chunk_list.cur_chunk, len, g_ko_fillmap_data);
998
999 grub_file_close(file);
1000 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1001 }
1002
1003 grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args)
1004 {
1005 int i;
1006 grub_uint8_t *byte;
1007 grub_uint32_t memsize;
1008 ventoy_image_desc *desc;
1009 grub_uint8_t flag[32] = {
1010 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
1011 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
1012 };
1013
1014 (void)ctxt;
1015 (void)argc;
1016 (void)args;
1017
1018 debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data);
1019
1020 if (!g_mod_new_data)
1021 {
1022 goto end;
1023 }
1024
1025 byte = (grub_uint8_t *)g_mod_new_data;
1026 for (i = 0; i < g_mod_new_len - 32; i += 16)
1027 {
1028 if (byte[i] == 0xFF && byte[i + 1] == 0xEE)
1029 {
1030 if (grub_memcmp(flag, byte + i, 32) == 0)
1031 {
1032 debug("Find position flag at %d(0x%x)\n", i, i);
1033 break;
1034 }
1035 }
1036 }
1037
1038 if (i >= g_mod_new_len - 32)
1039 {
1040 debug("Failed to find position flag %d\n", i);
1041 goto end;
1042 }
1043
1044 desc = (ventoy_image_desc *)(byte + i);
1045 desc->disk_size = g_ventoy_disk_size;
1046 desc->part1_size = g_ventoy_disk_part_size[0];
1047 grub_memcpy(desc->disk_uuid, g_ventoy_part_info->MBR.BootCode + 0x180, 16);
1048 grub_memcpy(desc->disk_signature, g_ventoy_part_info->MBR.BootCode + 0x1B8, 4);
1049
1050 desc->img_chunk_count = g_img_chunk_list.cur_chunk;
1051 memsize = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1052
1053 debug("image chunk count:%u memsize:%u\n", desc->img_chunk_count, memsize);
1054
1055 if (memsize >= VTOY_SIZE_1MB * 8)
1056 {
1057 grub_printf("image chunk count:%u memsize:%u too big\n", desc->img_chunk_count, memsize);
1058 goto end;
1059 }
1060
1061 grub_memcpy(desc + 1, g_img_chunk_list.chunk, memsize);
1062
1063 end:
1064 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1065 }
1066
1067 grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args)
1068 {
1069 int newlen;
1070 grub_uint8_t *buf;
1071
1072 (void)ctxt;
1073 (void)argc;
1074 (void)args;
1075
1076 debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data);
1077
1078 if (!g_mod_new_data)
1079 {
1080 goto end;
1081 }
1082
1083 buf = grub_malloc(g_mod_new_len);
1084 if (!buf)
1085 {
1086 goto end;
1087 }
1088
1089 newlen = ventoy_gzip_compress(g_mod_new_data, g_mod_new_len, buf, g_mod_new_len);
1090
1091 grub_free(g_mod_new_data);
1092
1093 debug("gzip org len:%d newlen:%d\n", g_mod_new_len, newlen);
1094
1095 g_mod_new_data = (char *)buf;
1096 g_mod_new_len = newlen;
1097
1098 end:
1099 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1100 }
1101
1102 grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1103 {
1104 int ventoy_compatible = 0;
1105 grub_uint32_t size = 0;
1106 grub_uint64_t isosize = 0;
1107 grub_uint32_t boot_catlog = 0;
1108 grub_uint32_t img_chunk_size = 0;
1109 grub_uint32_t override_count = 0;
1110 grub_uint32_t override_size = 0;
1111 grub_uint32_t virt_chunk_size = 0;
1112 grub_file_t file;
1113 grub_disk_t disk;
1114 const char *pLastChain = NULL;
1115 const char *compatible;
1116 ventoy_chain_head *chain;
1117 char envbuf[64];
1118
1119 (void)ctxt;
1120 (void)argc;
1121
1122 compatible = grub_env_get("ventoy_compatible");
1123 if (compatible && compatible[0] == 'Y')
1124 {
1125 ventoy_compatible = 1;
1126 }
1127
1128 if (NULL == g_img_chunk_list.chunk)
1129 {
1130 grub_printf("ventoy not ready\n");
1131 return 1;
1132 }
1133
1134 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1135 if (!file)
1136 {
1137 return 1;
1138 }
1139
1140 isosize = file->size;
1141
1142 boot_catlog = ventoy_get_iso_boot_catlog(file);
1143 if (boot_catlog)
1144 {
1145 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1146 {
1147 grub_env_set("LoadIsoEfiDriver", "on");
1148 }
1149 }
1150 else
1151 {
1152 if (ventoy_is_efi_os())
1153 {
1154 grub_env_set("LoadIsoEfiDriver", "on");
1155 }
1156 else
1157 {
1158 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1159 }
1160 }
1161
1162 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1163
1164 if (ventoy_compatible)
1165 {
1166 size = sizeof(ventoy_chain_head) + img_chunk_size;
1167 }
1168 else
1169 {
1170 override_count = ventoy_unix_get_override_chunk_count();
1171 override_size = override_count * sizeof(ventoy_override_chunk);
1172
1173 virt_chunk_size = ventoy_unix_get_virt_chunk_size();
1174 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1175 }
1176
1177 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1178 if (pLastChain)
1179 {
1180 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1181 if (chain)
1182 {
1183 debug("free last chain memory %p\n", chain);
1184 grub_free(chain);
1185 }
1186 }
1187
1188 chain = grub_malloc(size);
1189 if (!chain)
1190 {
1191 grub_printf("Failed to alloc chain memory size %u\n", size);
1192 grub_file_close(file);
1193 return 1;
1194 }
1195
1196 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1197 grub_env_set("vtoy_chain_mem_addr", envbuf);
1198 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1199 grub_env_set("vtoy_chain_mem_size", envbuf);
1200
1201 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1202
1203 /* part 1: os parameter */
1204 g_ventoy_chain_type = ventoy_chain_linux;
1205 ventoy_fill_os_param(file, &(chain->os_param));
1206
1207 /* part 2: chain head */
1208 disk = file->device->disk;
1209 chain->disk_drive = disk->id;
1210 chain->disk_sector_size = (1 << disk->log_sector_size);
1211 chain->real_img_size_in_bytes = file->size;
1212 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1213 chain->boot_catalog = boot_catlog;
1214
1215 if (!ventoy_is_efi_os())
1216 {
1217 grub_file_seek(file, boot_catlog * 2048);
1218 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1219 }
1220
1221 /* part 3: image chunk */
1222 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1223 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1224 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1225
1226 if (ventoy_compatible)
1227 {
1228 return 0;
1229 }
1230
1231 /* part 4: override chunk */
1232 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1233 chain->override_chunk_num = override_count;
1234 ventoy_unix_fill_override_data(isosize, chain);
1235
1236 /* part 5: virt chunk */
1237 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1238 chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count();
1239 ventoy_unix_fill_virt_data(isosize, chain);
1240
1241 grub_file_close(file);
1242
1243 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1244 }
1245