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