]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
1.0.07 release
[Ventoy.git] / GRUB2 / grub-2.04 / grub-core / ventoy / ventoy.c
1 /******************************************************************************
2 * ventoy.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
21 #include <grub/types.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/err.h>
25 #include <grub/dl.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
35 #include <grub/net.h>
36 #ifdef GRUB_MACHINE_EFI
37 #include <grub/efi/efi.h>
38 #endif
39 #include <grub/time.h>
40 #include <grub/ventoy.h>
41 #include "ventoy_def.h"
42
43 GRUB_MOD_LICENSE ("GPLv3+");
44
45 int g_ventoy_debug = 0;
46 static int g_efi_os = 0xFF;
47 initrd_info *g_initrd_img_list = NULL;
48 initrd_info *g_initrd_img_tail = NULL;
49 int g_initrd_img_count = 0;
50 int g_valid_initrd_count = 0;
51
52 static grub_file_t g_old_file;
53
54 char g_img_swap_tmp_buf[1024];
55
56 img_info *g_ventoy_img_list = NULL;
57 int g_ventoy_img_count = 0;
58
59 img_iterator_node g_img_iterator_head;
60
61 grub_uint8_t g_ventoy_break_level = 0;
62 grub_uint8_t g_ventoy_debug_level = 0;
63 grub_uint8_t *g_ventoy_cpio_buf = NULL;
64 grub_uint32_t g_ventoy_cpio_size = 0;
65 cpio_newc_header *g_ventoy_initrd_head = NULL;
66 grub_uint8_t *g_ventoy_runtime_buf = NULL;
67
68 ventoy_grub_param *g_grub_param = NULL;
69
70 ventoy_guid g_ventoy_guid = VENTOY_GUID;
71
72 ventoy_img_chunk_list g_img_chunk_list;
73
74 void ventoy_debug(const char *fmt, ...)
75 {
76 va_list args;
77
78 va_start (args, fmt);
79 grub_vprintf (fmt, args);
80 va_end (args);
81 }
82
83 int ventoy_is_efi_os(void)
84 {
85 if (g_efi_os > 1)
86 {
87 g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0;
88 }
89
90 return g_efi_os;
91 }
92
93 static int ventoy_string_check(const char *str, grub_char_check_func check)
94 {
95 if (!str)
96 {
97 return 0;
98 }
99
100 for ( ; *str; str++)
101 {
102 if (!check(*str))
103 {
104 return 0;
105 }
106 }
107
108 return 1;
109 }
110
111
112 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
113 {
114 grub_memcpy(buf, (char *)file->data + file->offset, len);
115 return len;
116 }
117
118 static grub_err_t ventoy_fs_close(grub_file_t file)
119 {
120 grub_file_close(g_old_file);
121 grub_free(file->data);
122
123 file->device = 0;
124 file->name = 0;
125
126 return 0;
127 }
128
129 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
130 {
131 int len;
132 grub_file_t file;
133 static struct grub_fs vtoy_fs =
134 {
135 .name = "vtoy",
136 .fs_dir = 0,
137 .fs_open = 0,
138 .fs_read = ventoy_fs_read,
139 .fs_close = ventoy_fs_close,
140 .fs_label = 0,
141 .next = 0
142 };
143
144 if (type != 52)
145 {
146 return rawFile;
147 }
148
149 file = (grub_file_t)grub_zalloc(sizeof (*file));
150 if (!file)
151 {
152 return 0;
153 }
154
155 file->data = grub_malloc(rawFile->size + 4096);
156 if (!file->data)
157 {
158 return 0;
159 }
160
161 grub_file_read(rawFile, file->data, rawFile->size);
162 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
163
164 g_old_file = rawFile;
165
166 file->size = rawFile->size + len;
167 file->device = rawFile->device;
168 file->fs = &vtoy_fs;
169 file->not_easily_seekable = 1;
170
171 return file;
172 }
173
174 static int ventoy_check_decimal_var(const char *name, long *value)
175 {
176 const char *value_str = NULL;
177
178 value_str = grub_env_get(name);
179 if (NULL == value_str)
180 {
181 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
182 }
183
184 if (!ventoy_is_decimal(value_str))
185 {
186 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
187 }
188
189 *value = grub_strtol(value_str, NULL, 10);
190
191 return GRUB_ERR_NONE;
192 }
193
194 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
195 {
196 if (argc != 1)
197 {
198 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
199 }
200
201 if (0 == grub_strcmp(args[0], "on"))
202 {
203 g_ventoy_debug = 1;
204 grub_env_set("vtdebug_flag", "debug");
205 }
206 else
207 {
208 g_ventoy_debug = 0;
209 grub_env_set("vtdebug_flag", "");
210 }
211
212 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
213 }
214
215 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
216 {
217 (void)ctxt;
218
219 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
220 {
221 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
222 grub_printf(" level:\r\n");
223 grub_printf(" 01/11: busybox / (+cat log)\r\n");
224 grub_printf(" 02/12: initrd / (+cat log)\r\n");
225 grub_printf(" 03/13: hook / (+cat log)\r\n");
226 grub_printf("\r\n");
227 grub_printf(" debug:\r\n");
228 grub_printf(" 0: debug is on\r\n");
229 grub_printf(" 1: debug is off\r\n");
230 grub_printf("\r\n");
231 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
232 }
233
234 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
235
236 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
237 {
238 g_ventoy_debug_level = 1;
239 }
240
241 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
242 }
243
244 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
245 {
246 long value_long = 0;
247 char buf[32];
248
249 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
250 {
251 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
252 }
253
254 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
255 {
256 return grub_errno;
257 }
258
259 value_long += grub_strtol(args[1], NULL, 10);
260
261 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
262 grub_env_set(args[0], buf);
263
264 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
265 }
266
267 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
268 {
269 int rc = 1;
270 char buf[32];
271 grub_file_t file;
272
273 (void)ctxt;
274 (void)argc;
275 (void)args;
276
277 if (argc != 2)
278 {
279 return rc;
280 }
281
282 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
283 if (file == NULL)
284 {
285 debug("failed to open file <%s> for udf check\n", args[0]);
286 return 1;
287 }
288
289 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
290
291 grub_env_set(args[1], buf);
292
293 grub_file_close(file);
294 rc = 0;
295
296 return rc;
297 }
298
299 static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
300 {
301 int rc = 1;
302 char name[32];
303 char value[32];
304 char *buf = NULL;
305 grub_file_t file;
306
307 (void)ctxt;
308 (void)argc;
309 (void)args;
310
311 if (argc != 2)
312 {
313 return rc;
314 }
315
316 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
317 if (file == NULL)
318 {
319 debug("failed to open file <%s> for udf check\n", args[0]);
320 return 1;
321 }
322
323 #ifdef GRUB_MACHINE_EFI
324 buf = (char *)grub_efi_allocate_iso_buf(file->size);
325 #else
326 buf = (char *)grub_malloc(file->size);
327 #endif
328
329 grub_file_read(file, buf, file->size);
330
331 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
332 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
333 grub_env_set(name, value);
334
335 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
336 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
337 grub_env_set(name, value);
338
339 grub_file_close(file);
340 rc = 0;
341
342 return rc;
343 }
344
345 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
346 {
347 int i;
348 int rc = 1;
349 grub_file_t file;
350 grub_uint8_t buf[32];
351
352 (void)ctxt;
353 (void)argc;
354 (void)args;
355
356 if (argc != 1)
357 {
358 return rc;
359 }
360
361 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
362 if (file == NULL)
363 {
364 debug("failed to open file <%s> for udf check\n", args[0]);
365 return 1;
366 }
367
368 for (i = 16; i < 32; i++)
369 {
370 grub_file_seek(file, i * 2048);
371 grub_file_read(file, buf, sizeof(buf));
372 if (buf[0] == 255)
373 {
374 break;
375 }
376 }
377
378 i++;
379 grub_file_seek(file, i * 2048);
380 grub_file_read(file, buf, sizeof(buf));
381
382 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
383 {
384 i++;
385 grub_file_seek(file, i * 2048);
386 grub_file_read(file, buf, sizeof(buf));
387
388 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
389 grub_memcmp(buf + 1, "NSR03", 5) == 0)
390 {
391 rc = 0;
392 }
393 }
394
395 grub_file_close(file);
396
397 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
398
399 return rc;
400 }
401
402 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
403 {
404 long value_long1 = 0;
405 long value_long2 = 0;
406
407 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
408 {
409 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
410 }
411
412 value_long1 = grub_strtol(args[0], NULL, 10);
413 value_long2 = grub_strtol(args[2], NULL, 10);
414
415 if (0 == grub_strcmp(args[1], "eq"))
416 {
417 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
418 }
419 else if (0 == grub_strcmp(args[1], "ne"))
420 {
421 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
422 }
423 else if (0 == grub_strcmp(args[1], "gt"))
424 {
425 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
426 }
427 else if (0 == grub_strcmp(args[1], "lt"))
428 {
429 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
430 }
431 else if (0 == grub_strcmp(args[1], "ge"))
432 {
433 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
434 }
435 else if (0 == grub_strcmp(args[1], "le"))
436 {
437 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
438 }
439 else
440 {
441 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
442 }
443
444 return grub_errno;
445 }
446
447 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
448 {
449 char *pos = NULL;
450 char buf[128] = {0};
451
452 if (argc != 2)
453 {
454 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
455 }
456
457 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
458 pos = grub_strstr(buf, ",");
459 if (pos)
460 {
461 *pos = 0;
462 }
463
464 grub_env_set(args[1], buf);
465
466 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
467 }
468
469 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
470 {
471 int i;
472 char buf[256];
473 grub_disk_t disk;
474 char *pos = NULL;
475 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
476
477 (void)ctxt;
478
479 if (argc != 1)
480 {
481 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
482 }
483
484 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
485 {
486 grub_snprintf(buf, sizeof(buf) - 1, "[ -e %s/%s ]", args[0], files[i]);
487 if (0 == grub_script_execute_sourcecode(buf))
488 {
489 debug("file %s exist, ventoy_compatible YES\n", buf);
490 grub_env_set("ventoy_compatible", "YES");
491 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
492 }
493 else
494 {
495 debug("file %s NOT exist\n", buf);
496 }
497 }
498
499 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
500 pos = grub_strstr(buf, ")");
501 if (pos)
502 {
503 *pos = 0;
504 }
505
506 disk = grub_disk_open(buf);
507 if (disk)
508 {
509 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
510 grub_disk_close(disk);
511
512 g_img_swap_tmp_buf[703] = 0;
513 for (i = 319; i < 703; i++)
514 {
515 if (g_img_swap_tmp_buf[i] == 'V' &&
516 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
517 {
518 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
519 grub_env_set("ventoy_compatible", "YES");
520 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
521 }
522 }
523 }
524 else
525 {
526 debug("failed to open disk <%s>\n", buf);
527 }
528
529 grub_env_set("ventoy_compatible", "NO");
530 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
531 }
532
533 static int ventoy_cmp_img(img_info *img1, img_info *img2)
534 {
535 char *s1, *s2;
536 int c1 = 0;
537 int c2 = 0;
538
539 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
540 {
541 c1 = *s1;
542 c2 = *s2;
543
544 if (grub_islower(c1))
545 {
546 c1 = c1 - 'a' + 'A';
547 }
548
549 if (grub_islower(c2))
550 {
551 c2 = c2 - 'a' + 'A';
552 }
553
554 if (c1 != c2)
555 {
556 break;
557 }
558 }
559
560 return (c1 - c2);
561 }
562
563 static void ventoy_swap_img(img_info *img1, img_info *img2)
564 {
565 grub_memcpy(g_img_swap_tmp_buf, img1->name, sizeof(img1->name));
566 grub_memcpy(img1->name, img2->name, sizeof(img1->name));
567 grub_memcpy(img2->name, g_img_swap_tmp_buf, sizeof(img1->name));
568
569 grub_memcpy(g_img_swap_tmp_buf, img1->path, sizeof(img1->path));
570 grub_memcpy(img1->path, img2->path, sizeof(img1->path));
571 grub_memcpy(img2->path, g_img_swap_tmp_buf, sizeof(img1->path));
572 }
573
574 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
575 {
576 grub_size_t i;
577
578 for (i = 0; i < namelen; i++)
579 {
580 if (filename[i] == ' ' || filename[i] == '\t')
581 {
582 return 0;
583 }
584
585 if ((grub_uint8_t)(filename[i]) >= 127)
586 {
587 return 0;
588 }
589 }
590
591 return 1;
592 }
593
594 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
595 {
596 grub_size_t len;
597 img_info *img;
598 img_info *tail;
599 img_iterator_node *new_node;
600 img_iterator_node *node = (img_iterator_node *)data;
601
602 len = grub_strlen(filename);
603
604 if (info->dir)
605 {
606 if ((len == 1 && filename[0] == '.') ||
607 (len == 2 && filename[0] == '.' && filename[1] == '.'))
608 {
609 return 0;
610 }
611
612 new_node = grub_malloc(sizeof(img_iterator_node));
613 if (new_node)
614 {
615 new_node->tail = node->tail;
616 grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
617
618 new_node->next = g_img_iterator_head.next;
619 g_img_iterator_head.next = new_node;
620 }
621 }
622 else
623 {
624 debug("Find a file %s\n", filename);
625
626 if ((len > 4) && (0 == grub_strcasecmp(filename + len - 4, ".iso")))
627 {
628 if (!ventoy_img_name_valid(filename, len))
629 {
630 return 0;
631 }
632
633 img = grub_zalloc(sizeof(img_info));
634 if (img)
635 {
636 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
637 grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, filename);
638
639 if (g_ventoy_img_list)
640 {
641 tail = *(node->tail);
642 img->prev = tail;
643 tail->next = img;
644 }
645 else
646 {
647 g_ventoy_img_list = img;
648 }
649
650 *((img_info **)(node->tail)) = img;
651 g_ventoy_img_count++;
652
653 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
654 }
655 }
656 }
657
658 return 0;
659 }
660
661 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
662 {
663 int len = GRUB_UINT_MAX;
664 const char *value = NULL;
665 char name[32] = {0};
666 char plat[32] = {0};
667 char guidstr[32] = {0};
668 ventoy_guid guid = VENTOY_GUID;
669 const char *fmt1 = NULL;
670 const char *fmt2 = NULL;
671 const char *fmt3 = NULL;
672 grub_uint32_t *puint = (grub_uint32_t *)name;
673 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
674 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
675 const char fmtcode[]={
676 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
677 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
678 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
679 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
680 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
681 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
682 };
683
684 grub_memset(name, 0, sizeof(name));
685 puint[0] = grub_swap_bytes32(0x56454e54);
686 puint[3] = grub_swap_bytes32(0x4f4e0000);
687 puint[2] = grub_swap_bytes32(0x45525349);
688 puint[1] = grub_swap_bytes32(0x4f595f56);
689 value = ventoy_get_env(name);
690
691 grub_memset(name, 0, sizeof(name));
692 puint[1] = grub_swap_bytes32(0x5f544f50);
693 puint[0] = grub_swap_bytes32(0x56544c45);
694 fmt1 = ventoy_get_env(name);
695 if (!fmt1)
696 {
697 fmt1 = fmtdata;
698 }
699
700 grub_memset(name, 0, sizeof(name));
701 puint[1] = grub_swap_bytes32(0x5f4c4654);
702 puint[0] = grub_swap_bytes32(0x56544c45);
703 fmt2 = ventoy_get_env(name);
704
705 grub_memset(name, 0, sizeof(name));
706 puint[1] = grub_swap_bytes32(0x5f434c52);
707 puint[0] = grub_swap_bytes32(0x56544c45);
708 fmt3 = ventoy_get_env(name);
709
710 grub_memcpy(guidstr, &guid, sizeof(guid));
711
712 #if defined (GRUB_MACHINE_EFI)
713 puint2[0] = grub_swap_bytes32(0x55454649);
714 #else
715 puint2[0] = grub_swap_bytes32(0x42494f53);
716 #endif
717
718 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
719 #pragma GCC diagnostic push
720 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
721 len = grub_snprintf(buffer, buflen, fmtcode,
722 fmt1 ? fmt1 : fmtdata,
723 fmt2 ? fmt2 : fmtdata + 4,
724 value ? value : "", plat, guidstr,
725 fmt3 ? fmt3 : fmtdata + 6);
726 #pragma GCC diagnostic pop
727
728 grub_memset(name, 0, sizeof(name));
729 puint[0] = grub_swap_bytes32(0x76746f79);
730 puint[2] = grub_swap_bytes32(0x656e7365);
731 puint[1] = grub_swap_bytes32(0x5f6c6963);
732 ventoy_set_env(name, guidstr);
733
734 return len;
735 }
736
737 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
738 {
739 grub_fs_t fs;
740 grub_device_t dev = NULL;
741 img_info *cur = NULL;
742 img_info *tail = NULL;
743 char *device_name = NULL;
744 char buf[32];
745 img_iterator_node *node = NULL;
746
747 (void)ctxt;
748
749 if (argc != 2)
750 {
751 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
752 }
753
754 if (g_ventoy_img_list || g_ventoy_img_count)
755 {
756 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
757 }
758
759 device_name = grub_file_get_device_name(args[0]);
760 if (!device_name)
761 {
762 goto fail;
763 }
764
765 dev = grub_device_open(device_name);
766 if (!dev)
767 {
768 goto fail;
769 }
770
771 fs = grub_fs_probe(dev);
772 if (!fs)
773 {
774 goto fail;
775 }
776
777 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
778
779 g_img_iterator_head.tail = &tail;
780 grub_strcpy(g_img_iterator_head.dir, "/");
781
782 fs->fs_dir(dev, "/", ventoy_colect_img_files, &g_img_iterator_head);
783
784 while (g_img_iterator_head.next)
785 {
786 node = g_img_iterator_head.next;
787 g_img_iterator_head.next = node->next;
788
789 fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
790 grub_free(node);
791 }
792
793 /* sort image list by image name */
794 for (cur = g_ventoy_img_list; cur; cur = cur->next)
795 {
796 for (tail = cur->next; tail; tail = tail->next)
797 {
798 if (ventoy_cmp_img(cur, tail) > 0)
799 {
800 ventoy_swap_img(cur, tail);
801 }
802 }
803 }
804
805 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
806 grub_env_set(args[1], buf);
807
808 fail:
809
810 check_free(device_name, grub_free);
811 check_free(dev, grub_device_close);
812
813 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
814 }
815
816
817 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
818 {
819 img_info *next = NULL;
820 img_info *cur = g_ventoy_img_list;
821
822 (void)ctxt;
823 (void)argc;
824 (void)args;
825
826 while (cur)
827 {
828 next = cur->next;
829 grub_free(cur);
830 cur = next;
831 }
832
833 g_ventoy_img_list = NULL;
834 g_ventoy_img_count = 0;
835
836 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
837 }
838
839 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
840 {
841 long img_id = 0;
842 img_info *cur = g_ventoy_img_list;
843
844 (void)ctxt;
845
846 if (argc != 2 || (!ventoy_is_decimal(args[0])))
847 {
848 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
849 }
850
851 img_id = grub_strtol(args[0], NULL, 10);
852 if (img_id >= g_ventoy_img_count)
853 {
854 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
855 }
856
857 debug("Find image %ld name \n", img_id);
858
859 while (cur && img_id > 0)
860 {
861 img_id--;
862 cur = cur->next;
863 }
864
865 if (!cur)
866 {
867 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
868 }
869
870 debug("image name is %s\n", cur->name);
871
872 grub_env_set(args[1], cur->name);
873
874 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
875 }
876
877 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
878 {
879 const char *name = NULL;
880 img_info *cur = g_ventoy_img_list;
881
882 (void)ctxt;
883
884 if (argc != 1)
885 {
886 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
887 }
888
889 name = grub_env_get("chosen");
890
891 while (cur)
892 {
893 if (0 == grub_strcmp(name, cur->name))
894 {
895 grub_env_set(args[0], cur->path);
896 break;
897 }
898 cur = cur->next;
899 }
900
901 if (!cur)
902 {
903 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
904 }
905
906 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
907 }
908
909 static int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid)
910 {
911 grub_disk_t disk;
912 char *device_name;
913 char *pos;
914 char *pos2;
915
916 device_name = grub_file_get_device_name(filename);
917 if (!device_name)
918 {
919 return 1;
920 }
921
922 pos = device_name;
923 if (pos[0] == '(')
924 {
925 pos++;
926 }
927
928 pos2 = grub_strstr(pos, ",");
929 if (!pos2)
930 {
931 pos2 = grub_strstr(pos, ")");
932 }
933
934 if (pos2)
935 {
936 *pos2 = 0;
937 }
938
939 disk = grub_disk_open(pos);
940 if (disk)
941 {
942 grub_disk_read(disk, 0, 0x180, 16, guid);
943 grub_disk_close(disk);
944 }
945 else
946 {
947 return 1;
948 }
949
950 grub_free(device_name);
951 return 0;
952 }
953
954 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
955 {
956 eltorito_descriptor desc;
957
958 grub_memset(&desc, 0, sizeof(desc));
959 grub_file_seek(file, 17 * 2048);
960 grub_file_read(file, &desc, sizeof(desc));
961
962 if (desc.type != 0 || desc.version != 1)
963 {
964 return 0;
965 }
966
967 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
968 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
969 {
970 return 0;
971 }
972
973 return desc.sector;
974 }
975
976 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
977 {
978 int i;
979 grub_uint8_t buf[512];
980
981 grub_file_seek(file, sector * 2048);
982 grub_file_read(file, buf, sizeof(buf));
983
984 if (buf[0] == 0x01 && buf[1] == 0xEF)
985 {
986 debug("%s efi eltorito in Validation Entry\n", file->name);
987 return 1;
988 }
989
990 for (i = 64; i < (int)sizeof(buf); i += 32)
991 {
992 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
993 {
994 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
995 return 1;
996 }
997 }
998
999 debug("%s does not contain efi eltorito\n", file->name);
1000 return 0;
1001 }
1002
1003 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
1004 {
1005 char *pos;
1006 grub_uint32_t i;
1007 grub_uint8_t chksum = 0;
1008 grub_disk_t disk;
1009
1010 disk = file->device->disk;
1011 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
1012
1013 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
1014 param->vtoy_disk_part_id = disk->partition->number + 1;
1015
1016 if (grub_strcmp(file->fs->name, "exfat") == 0)
1017 {
1018 param->vtoy_disk_part_type = 0;
1019 }
1020 else if (grub_strcmp(file->fs->name, "ntfs") == 0)
1021 {
1022 param->vtoy_disk_part_type = 1;
1023 }
1024 else
1025 {
1026 param->vtoy_disk_part_type = 0xFFFF;
1027 }
1028
1029 pos = grub_strstr(file->name, "/");
1030 if (!pos)
1031 {
1032 pos = file->name;
1033 }
1034
1035 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
1036
1037 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid);
1038
1039 param->vtoy_img_size = file->size;
1040
1041 param->vtoy_reserved[0] = g_ventoy_break_level;
1042 param->vtoy_reserved[1] = g_ventoy_debug_level;
1043
1044 /* calculate checksum */
1045 for (i = 0; i < sizeof(ventoy_os_param); i++)
1046 {
1047 chksum += *((grub_uint8_t *)param + i);
1048 }
1049 param->chksum = (grub_uint8_t)(0x100 - chksum);
1050
1051 return;
1052 }
1053
1054 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1055 {
1056 grub_file_t file;
1057
1058 (void)ctxt;
1059 (void)argc;
1060
1061 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1062 if (!file)
1063 {
1064 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
1065 }
1066
1067 if (g_img_chunk_list.chunk)
1068 {
1069 grub_free(g_img_chunk_list.chunk);
1070 }
1071
1072 /* get image chunk data */
1073 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
1074 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1075 if (NULL == g_img_chunk_list.chunk)
1076 {
1077 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1078 }
1079
1080 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1081 g_img_chunk_list.cur_chunk = 0;
1082
1083 debug("get fat file chunk part start:%llu\n", (unsigned long long)file->device->disk->partition->start);
1084 grub_fat_get_file_chunk(file->device->disk->partition->start, file, &g_img_chunk_list);
1085
1086 grub_file_close(file);
1087
1088 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
1089
1090 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1091 }
1092
1093 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
1094 {
1095 grub_uint32_t i;
1096 ventoy_img_chunk *cur;
1097
1098 (void)ctxt;
1099 (void)argc;
1100 (void)args;
1101
1102 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
1103 {
1104 cur = g_img_chunk_list.chunk + i;
1105 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1106 cur->img_start_sector, cur->img_end_sector,
1107 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
1108 );
1109 }
1110
1111 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1112 }
1113
1114 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
1115 {
1116 int i;
1117 ventoy_grub_param_file_replace *replace = NULL;
1118
1119 (void)ctxt;
1120 (void)argc;
1121 (void)args;
1122
1123 if (argc >= 2)
1124 {
1125 replace = &(g_grub_param->file_replace);
1126 replace->magic = GRUB_FILE_REPLACE_MAGIC;
1127
1128 replace->old_name_cnt = 0;
1129 for (i = 0; i < 4 && i + 1 < argc; i++)
1130 {
1131 replace->old_name_cnt++;
1132 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
1133 }
1134
1135 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
1136 }
1137
1138 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1139 }
1140
1141 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
1142 {
1143 va_list ap;
1144 grub_file_t file;
1145 char fullpath[256] = {0};
1146
1147 va_start (ap, fmt);
1148 grub_vsnprintf(fullpath, 255, fmt, ap);
1149 va_end (ap);
1150
1151 file = grub_file_open(fullpath, type);
1152 if (!file)
1153 {
1154 debug("grub_file_open failed <%s>\n", fullpath);
1155 grub_errno = 0;
1156 }
1157
1158 return file;
1159 }
1160
1161 int ventoy_is_file_exist(const char *fmt, ...)
1162 {
1163 va_list ap;
1164 int len;
1165 char *pos = NULL;
1166 char buf[256] = {0};
1167
1168 grub_snprintf(buf, sizeof(buf), "%s", "[ -f ");
1169 pos = buf + 5;
1170
1171 va_start (ap, fmt);
1172 len = grub_vsnprintf(pos, 255, fmt, ap);
1173 va_end (ap);
1174
1175 grub_strncpy(pos + len, " ]", 2);
1176
1177 debug("script exec %s\n", buf);
1178
1179 if (0 == grub_script_execute_sourcecode(buf))
1180 {
1181 return 1;
1182 }
1183
1184 return 0;
1185 }
1186
1187 static int ventoy_env_init(void)
1188 {
1189 char buf[64];
1190
1191 grub_env_set("vtdebug_flag", "");
1192
1193 ventoy_filt_register(0, ventoy_wrapper_open);
1194
1195 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
1196 if (g_grub_param)
1197 {
1198 g_grub_param->grub_env_get = grub_env_get;
1199 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
1200 grub_env_set("env_param", buf);
1201 }
1202
1203 return 0;
1204 }
1205
1206 static cmd_para ventoy_cmds[] =
1207 {
1208 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
1209 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1210 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
1211 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
1212 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
1213 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
1214 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
1215 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
1216 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
1217 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
1218 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
1219 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
1220 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
1221 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
1222
1223 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
1224 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
1225 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
1226
1227 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1228 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
1229 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
1230 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
1231 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
1232 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
1233 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
1234 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
1235 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
1236
1237 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
1238 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
1239 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
1240
1241 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
1242
1243
1244 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
1245 };
1246
1247
1248
1249 GRUB_MOD_INIT(ventoy)
1250 {
1251 grub_uint32_t i;
1252 cmd_para *cur = NULL;
1253
1254 ventoy_env_init();
1255
1256 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1257 {
1258 cur = ventoy_cmds + i;
1259 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
1260 cur->summary, cur->description, cur->parser);
1261 }
1262 }
1263
1264 GRUB_MOD_FINI(ventoy)
1265 {
1266 grub_uint32_t i;
1267
1268 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
1269 {
1270 grub_unregister_extcmd(ventoy_cmds[i].cmd);
1271 }
1272 }
1273