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