]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c
708d6f2222ab2eed3f6ee4ac3be1bb0d5041e7c6
[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("NAS version:<%s>\n", ver);
449 if (grub_strncmp(ver, "TrueNAS-", 8) == 0)
450 {
451 ver += 8;
452 }
453 ventoy_set_env(args[1], ver);
454 }
455 else
456 {
457 debug("NAS version:<%s>\n", "NOT FOUND");
458 grub_env_unset(args[1]);
459 }
460
461 end:
462 grub_check_free(buf);
463 check_free(json, vtoy_json_destroy);
464 grub_file_close(file);
465
466 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
467 }
468
469 grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args)
470 {
471 grub_file_t file;
472 char *buf;
473 char *start = NULL;
474 char *nextline = NULL;
475
476 (void)ctxt;
477 (void)argc;
478 (void)args;
479
480 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
481 if (!file)
482 {
483 debug("Failed to open file %s\n", args[0]);
484 return 1;
485 }
486
487 buf = grub_zalloc(file->size + 2);
488 if (!buf)
489 {
490 grub_file_close(file);
491 return 0;
492 }
493 grub_file_read(file, buf, file->size);
494
495 for (start = buf; start; start = nextline)
496 {
497 if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0)
498 {
499 nextline = start;
500 while (*nextline && *nextline != '\r' && *nextline != '\n')
501 {
502 nextline++;
503 }
504
505 *nextline = 0;
506 break;
507 }
508 nextline = ventoy_get_line(start);
509 }
510
511 if (start)
512 {
513 debug("freebsd version:<%s>\n", start);
514 ventoy_set_env(args[1], start);
515 }
516 else
517 {
518 debug("freebsd version:<%s>\n", "NOT FOUND");
519 grub_env_unset(args[1]);
520 }
521
522 grub_free(buf);
523 grub_file_close(file);
524
525 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
526 }
527
528 grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args)
529 {
530 int j;
531 int k;
532 grub_elf_t elf = NULL;
533 grub_off_t offset = 0;
534 grub_uint32_t len = 0;
535 char *str = NULL;
536 char *data = NULL;
537 void *hdr = NULL;
538 char ver[64] = {0};
539
540 (void)ctxt;
541 (void)argc;
542 (void)args;
543
544 if (argc != 3)
545 {
546 debug("Invalid argc %d\n", argc);
547 return 1;
548 }
549
550 data = grub_zalloc(8192);
551 if (!data)
552 {
553 goto out;
554 }
555
556 elf = grub_elf_open(args[0], GRUB_FILE_TYPE_LINUX_INITRD);
557 if (!elf)
558 {
559 debug("Failed to open file %s\n", args[0]);
560 goto out;
561 }
562
563 if (args[1][0] == '6')
564 {
565 Elf64_Ehdr *e = &(elf->ehdr.ehdr64);
566 Elf64_Shdr *h;
567 Elf64_Shdr *s;
568 Elf64_Shdr *t;
569 Elf64_Half i;
570
571 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
572 if (!h)
573 {
574 goto out;
575 }
576
577 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
578 grub_file_seek(elf->file, e->e_shoff);
579 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
580
581 s = (Elf64_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
582 str = grub_malloc(s->sh_size + 1);
583 if (!str)
584 {
585 goto out;
586 }
587 str[s->sh_size] = 0;
588
589 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
590 grub_file_seek(elf->file, s->sh_offset);
591 grub_file_read(elf->file, str, s->sh_size);
592
593 for (t = h, i = 0; i < e->e_shnum; i++)
594 {
595 if (grub_strcmp(str + t->sh_name, ".data") == 0)
596 {
597 offset = t->sh_offset;
598 len = t->sh_size;
599 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
600 break;
601 }
602 t = (Elf64_Shdr *)((char *)t + e->e_shentsize);
603 }
604 }
605 else
606 {
607 Elf32_Ehdr *e = &(elf->ehdr.ehdr32);
608 Elf32_Shdr *h;
609 Elf32_Shdr *s;
610 Elf32_Shdr *t;
611 Elf32_Half i;
612
613 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
614 if (!h)
615 {
616 goto out;
617 }
618
619 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
620 grub_file_seek(elf->file, e->e_shoff);
621 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
622
623 s = (Elf32_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
624 str = grub_malloc(s->sh_size + 1);
625 if (!str)
626 {
627 goto out;
628 }
629 str[s->sh_size] = 0;
630
631 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
632 grub_file_seek(elf->file, s->sh_offset);
633 grub_file_read(elf->file, str, s->sh_size);
634
635 for (t = h, i = 0; i < e->e_shnum; i++)
636 {
637 if (grub_strcmp(str + t->sh_name, ".data") == 0)
638 {
639 offset = t->sh_offset;
640 len = t->sh_size;
641 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
642 break;
643 }
644 t = (Elf32_Shdr *)((char *)t + e->e_shentsize);
645 }
646 }
647
648 if (offset == 0 || len == 0)
649 {
650 debug(".data section not found %s\n", args[0]);
651 goto out;
652 }
653
654 grub_file_seek(elf->file, offset + len - 8192);
655 grub_file_read(elf->file, data, 8192);
656
657 for (j = 0; j < 8192 - 12; j++)
658 {
659 if (grub_strncmp(data + j, "@(#)FreeBSD ", 12) == 0)
660 {
661 for (k = j + 12; k < 8192; k++)
662 {
663 if (0 == grub_isdigit(data[k]) && data[k] != '.')
664 {
665 data[k] = 0;
666 break;
667 }
668 }
669
670 grub_snprintf(ver, sizeof(ver), "%s", data + j + 12);
671 break;
672 }
673 }
674
675 if (ver[0])
676 {
677 k = (int)grub_strtoul(ver, NULL, 10);
678 debug("freebsd version:<%s> <%d.x>\n", ver, k);
679 grub_snprintf(ver, sizeof(ver), "%d.x", k);
680 ventoy_set_env(args[2], ver);
681 }
682 else
683 {
684 debug("freebsd version:<%s>\n", "NOT FOUND");
685 }
686
687 out:
688 grub_check_free(str);
689 grub_check_free(hdr);
690 grub_check_free(data);
691 check_free(elf, grub_elf_close);
692
693 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
694 }
695
696 grub_err_t ventoy_cmd_unix_replace_grub_conf(grub_extcmd_context_t ctxt, int argc, char **args)
697 {
698 int len = 0;
699 grub_uint32_t i;
700 char *data;
701 char *pos;
702 const char *val = NULL;
703 grub_uint64_t offset;
704 grub_file_t file;
705 char extcfg[512];
706 const char *confile = NULL;
707 const char * loader_conf[] =
708 {
709 "/boot/grub/grub.cfg",
710 };
711
712 (void)ctxt;
713
714 if (argc != 1 && argc != 2)
715 {
716 debug("Replace conf invalid argc %d\n", argc);
717 return 1;
718 }
719
720 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
721 {
722 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
723 {
724 confile = loader_conf[i];
725 g_conf_override_offset = offset;
726 break;
727 }
728 }
729
730 if (confile == NULL)
731 {
732 debug("Can't find grub.cfg file from %u locations\n", i);
733 return 1;
734 }
735
736 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
737 if (!file)
738 {
739 debug("Failed to open %s \n", confile);
740 return 1;
741 }
742
743 debug("old grub2 conf file size:%d\n", (int)file->size);
744
745 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
746 if (!data)
747 {
748 grub_file_close(file);
749 return 1;
750 }
751
752 grub_file_read(file, data, file->size);
753 grub_file_close(file);
754
755 g_conf_new_data = data;
756 g_conf_new_len = (int)file->size;
757
758 pos = grub_strstr(data, "kfreebsd /boot/kernel/kernel");
759 if (pos)
760 {
761 pos += grub_strlen("kfreebsd /boot/kernel/kernel");
762 if (grub_strncmp(pos, ".gz", 3) == 0)
763 {
764 pos += 3;
765 }
766
767 if (argc == 2)
768 {
769 vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s; set kFreeBSD.hint.ventoy.0.alias=\"%s\"", args[0], args[1]);
770 }
771 else
772 {
773 vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s", args[0]);
774 }
775
776 if (g_unix_vlnk_boot)
777 {
778 vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.vlnk=%d", 1);
779 }
780
781 val = ventoy_get_env("VTOY_UNIX_REMOUNT");
782 if (val && val[0] == '1' && val[1] == 0)
783 {
784 vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.remount=%d", 1);
785 }
786
787 grub_memmove(pos + len, pos, (int)(file->size - (pos - data)));
788 grub_memcpy(pos, extcfg, len);
789 g_conf_new_len += len;
790 }
791 else
792 {
793 debug("no kfreebsd found\n");
794 }
795
796 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
797 }
798
799 grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args)
800 {
801 grub_uint32_t i;
802 char *data;
803 grub_uint64_t offset;
804 grub_file_t file;
805 const char *confile = NULL;
806 const char * loader_conf[] =
807 {
808 "/boot/loader.conf",
809 "/boot/defaults/loader.conf",
810 };
811
812 (void)ctxt;
813
814 if (argc != 2 && argc != 3)
815 {
816 debug("Replace conf invalid argc %d\n", argc);
817 return 1;
818 }
819
820 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
821 {
822 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
823 {
824 confile = loader_conf[i];
825 g_conf_override_offset = offset;
826 break;
827 }
828 }
829
830 if (confile == NULL)
831 {
832 debug("Can't find loader.conf file from %u locations\n", i);
833 return 1;
834 }
835
836 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
837 if (!file)
838 {
839 debug("Failed to open %s \n", confile);
840 return 1;
841 }
842
843 debug("old conf file <%s> size:%d\n", confile, (int)file->size);
844
845 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
846 if (!data)
847 {
848 grub_file_close(file);
849 return 1;
850 }
851
852 grub_file_read(file, data, file->size);
853 grub_file_close(file);
854
855 g_conf_new_data = data;
856 g_conf_new_len = (int)file->size;
857
858 if (grub_strcmp(args[0], "FreeBSD") == 0)
859 {
860 g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1], (argc > 2) ? args[2] : NULL);
861 }
862 else if (grub_strcmp(args[0], "DragonFly") == 0)
863 {
864 g_conf_new_len += ventoy_dragonfly_append_conf(data + file->size, args[1]);
865 }
866
867 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
868 }
869
870 static int ventoy_unix_search_magic(char *data, int len)
871 {
872 int i;
873 grub_uint32_t *magic = NULL;
874
875 for (i = 0; i < len; i += 4096)
876 {
877 magic = (grub_uint32_t *)(data + i);
878 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
879 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
880 {
881 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 12));
882 g_mod_search_magic = i;
883 return 0;
884 }
885 }
886
887 debug("unix can not find search magic\n");
888 return 1;
889 }
890
891 grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args)
892 {
893 char *data;
894 grub_uint64_t offset;
895 grub_file_t file;
896
897 (void)ctxt;
898
899 if (argc != 2)
900 {
901 debug("Replace ko invalid argc %d\n", argc);
902 return 1;
903 }
904
905 debug("replace ko %s\n", args[0]);
906
907 if (ventoy_get_file_override(args[0], &offset) == 0)
908 {
909 grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]);
910 g_mod_override_offset = offset;
911 }
912 else
913 {
914 debug("Can't find replace ko file from %s\n", args[0]);
915 return 1;
916 }
917
918 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]);
919 if (!file)
920 {
921 debug("Failed to open %s \n", args[1]);
922 return 1;
923 }
924
925 debug("new ko file size:%d\n", (int)file->size);
926
927 data = grub_malloc(file->size);
928 if (!data)
929 {
930 debug("Failed to alloc memory for new ko %d\n", (int)file->size);
931 grub_file_close(file);
932 return 1;
933 }
934
935 grub_file_read(file, data, file->size);
936 grub_file_close(file);
937
938 g_mod_new_data = data;
939 g_mod_new_len = (int)file->size;
940
941 ventoy_unix_search_magic(g_mod_new_data, g_mod_new_len);
942
943 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
944 }
945
946 grub_err_t ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt, int argc, char **args)
947 {
948 int i;
949 grub_file_t file;
950 grub_uint32_t magic[4];
951 grub_uint32_t len;
952
953 (void)ctxt;
954
955 if (argc != 1)
956 {
957 debug("Fillmap ko invalid argc %d\n", argc);
958 return 1;
959 }
960
961 debug("Fillmap ko %s\n", args[0]);
962
963 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", args[0]);
964 if (file)
965 {
966 grub_file_read(file, magic, 4); /* read for trigger */
967 g_mod_override_offset = grub_iso9660_get_last_read_pos(file);
968 }
969 else
970 {
971 debug("Can't find replace ko file from %s\n", args[0]);
972 return 1;
973 }
974
975 for (i = 0; i < (int)(file->size); i += 65536)
976 {
977 magic[0] = 0;
978 grub_file_seek(file, i);
979 grub_file_read(file, magic, sizeof(magic));
980
981 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
982 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
983 {
984 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 16));
985 g_mod_override_offset += i;
986 break;
987 }
988 }
989
990 len = (grub_uint32_t)OFFSET_OF(struct g_ventoy_map, seglist) +
991 (sizeof(struct g_ventoy_seg) * g_img_chunk_list.cur_chunk);
992
993 g_ko_fillmap_len = (int)len;
994 g_ko_fillmap_data = grub_malloc(len);
995 if (!g_ko_fillmap_data)
996 {
997 g_ko_fillmap_len = 0;
998 debug("Failed to malloc fillmap data\n");
999 }
1000
1001 debug("Fillmap ko segnum:%u, override len:%u data:%p\n", g_img_chunk_list.cur_chunk, len, g_ko_fillmap_data);
1002
1003 grub_file_close(file);
1004 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1005 }
1006
1007 grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args)
1008 {
1009 int i;
1010 grub_uint8_t *byte;
1011 grub_uint32_t memsize;
1012 ventoy_image_desc *desc;
1013 grub_uint8_t flag[32] = {
1014 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
1015 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
1016 };
1017
1018 (void)ctxt;
1019 (void)argc;
1020 (void)args;
1021
1022 debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data);
1023
1024 if (!g_mod_new_data)
1025 {
1026 goto end;
1027 }
1028
1029 byte = (grub_uint8_t *)g_mod_new_data;
1030 for (i = 0; i < g_mod_new_len - 32; i += 16)
1031 {
1032 if (byte[i] == 0xFF && byte[i + 1] == 0xEE)
1033 {
1034 if (grub_memcmp(flag, byte + i, 32) == 0)
1035 {
1036 debug("Find position flag at %d(0x%x)\n", i, i);
1037 break;
1038 }
1039 }
1040 }
1041
1042 if (i >= g_mod_new_len - 32)
1043 {
1044 debug("Failed to find position flag %d\n", i);
1045 goto end;
1046 }
1047
1048 desc = (ventoy_image_desc *)(byte + i);
1049 desc->disk_size = g_ventoy_disk_size;
1050 desc->part1_size = g_ventoy_disk_part_size[0];
1051 grub_memcpy(desc->disk_uuid, g_ventoy_part_info->MBR.BootCode + 0x180, 16);
1052 grub_memcpy(desc->disk_signature, g_ventoy_part_info->MBR.BootCode + 0x1B8, 4);
1053
1054 desc->img_chunk_count = g_img_chunk_list.cur_chunk;
1055 memsize = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1056
1057 debug("image chunk count:%u memsize:%u\n", desc->img_chunk_count, memsize);
1058
1059 if (memsize >= VTOY_SIZE_1MB * 8)
1060 {
1061 grub_printf("image chunk count:%u memsize:%u too big\n", desc->img_chunk_count, memsize);
1062 goto end;
1063 }
1064
1065 grub_memcpy(desc + 1, g_img_chunk_list.chunk, memsize);
1066
1067 end:
1068 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1069 }
1070
1071 grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args)
1072 {
1073 int newlen;
1074 grub_uint8_t *buf;
1075
1076 (void)ctxt;
1077 (void)argc;
1078 (void)args;
1079
1080 debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data);
1081
1082 if (!g_mod_new_data)
1083 {
1084 goto end;
1085 }
1086
1087 buf = grub_malloc(g_mod_new_len);
1088 if (!buf)
1089 {
1090 goto end;
1091 }
1092
1093 newlen = ventoy_gzip_compress(g_mod_new_data, g_mod_new_len, buf, g_mod_new_len);
1094
1095 grub_free(g_mod_new_data);
1096
1097 debug("gzip org len:%d newlen:%d\n", g_mod_new_len, newlen);
1098
1099 g_mod_new_data = (char *)buf;
1100 g_mod_new_len = newlen;
1101
1102 end:
1103 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1104 }
1105
1106 grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1107 {
1108 int ventoy_compatible = 0;
1109 grub_uint32_t size = 0;
1110 grub_uint64_t isosize = 0;
1111 grub_uint32_t boot_catlog = 0;
1112 grub_uint32_t img_chunk_size = 0;
1113 grub_uint32_t override_count = 0;
1114 grub_uint32_t override_size = 0;
1115 grub_uint32_t virt_chunk_size = 0;
1116 grub_file_t file;
1117 grub_disk_t disk;
1118 const char *pLastChain = NULL;
1119 const char *compatible;
1120 ventoy_chain_head *chain;
1121 char envbuf[64];
1122
1123 (void)ctxt;
1124 (void)argc;
1125
1126 compatible = grub_env_get("ventoy_compatible");
1127 if (compatible && compatible[0] == 'Y')
1128 {
1129 ventoy_compatible = 1;
1130 }
1131
1132 if (NULL == g_img_chunk_list.chunk)
1133 {
1134 grub_printf("ventoy not ready\n");
1135 return 1;
1136 }
1137
1138 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1139 if (!file)
1140 {
1141 return 1;
1142 }
1143
1144 isosize = file->size;
1145
1146 boot_catlog = ventoy_get_iso_boot_catlog(file);
1147 if (boot_catlog)
1148 {
1149 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1150 {
1151 grub_env_set("LoadIsoEfiDriver", "on");
1152 }
1153 }
1154 else
1155 {
1156 if (ventoy_is_efi_os())
1157 {
1158 grub_env_set("LoadIsoEfiDriver", "on");
1159 }
1160 else
1161 {
1162 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1163 }
1164 }
1165
1166 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1167
1168 if (ventoy_compatible)
1169 {
1170 size = sizeof(ventoy_chain_head) + img_chunk_size;
1171 }
1172 else
1173 {
1174 override_count = ventoy_unix_get_override_chunk_count();
1175 override_size = override_count * sizeof(ventoy_override_chunk);
1176
1177 virt_chunk_size = ventoy_unix_get_virt_chunk_size();
1178 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1179 }
1180
1181 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1182 if (pLastChain)
1183 {
1184 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1185 if (chain)
1186 {
1187 debug("free last chain memory %p\n", chain);
1188 grub_free(chain);
1189 }
1190 }
1191
1192 chain = ventoy_alloc_chain(size);
1193 if (!chain)
1194 {
1195 grub_printf("Failed to alloc chain unix memory size %u\n", size);
1196 grub_file_close(file);
1197 return 1;
1198 }
1199
1200 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1201 grub_env_set("vtoy_chain_mem_addr", envbuf);
1202 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1203 grub_env_set("vtoy_chain_mem_size", envbuf);
1204
1205 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1206
1207 /* part 1: os parameter */
1208 g_ventoy_chain_type = ventoy_chain_linux;
1209 ventoy_fill_os_param(file, &(chain->os_param));
1210
1211 /* part 2: chain head */
1212 disk = file->device->disk;
1213 chain->disk_drive = disk->id;
1214 chain->disk_sector_size = (1 << disk->log_sector_size);
1215 chain->real_img_size_in_bytes = file->size;
1216 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1217 chain->boot_catalog = boot_catlog;
1218
1219 if (!ventoy_is_efi_os())
1220 {
1221 grub_file_seek(file, boot_catlog * 2048);
1222 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1223 }
1224
1225 /* part 3: image chunk */
1226 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1227 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1228 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1229
1230 if (ventoy_compatible)
1231 {
1232 return 0;
1233 }
1234
1235 /* part 4: override chunk */
1236 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1237 chain->override_chunk_num = override_count;
1238 ventoy_unix_fill_override_data(isosize, chain);
1239
1240 /* part 5: virt chunk */
1241 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1242 chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count();
1243 ventoy_unix_fill_virt_data(isosize, chain);
1244
1245 grub_file_close(file);
1246
1247 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1248 }
1249