]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
4b0d95b62b2bd13ff8d2b61f5ad91b0c3348be0f
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_cmd.c
1 /******************************************************************************
2 * ventoy_cmd.c
3 *
4 * Copyright (c) 2021, 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/misc.h>
37 #include <grub/kernel.h>
38 #ifdef GRUB_MACHINE_EFI
39 #include <grub/efi/api.h>
40 #include <grub/efi/efi.h>
41 #endif
42 #include <grub/time.h>
43 #include <grub/video.h>
44 #include <grub/acpi.h>
45 #include <grub/charset.h>
46 #include <grub/crypto.h>
47 #include <grub/lib/crc.h>
48 #include <grub/ventoy.h>
49 #include "ventoy_def.h"
50 #include "miniz.h"
51
52 GRUB_MOD_LICENSE ("GPLv3+");
53
54 static grub_uint8_t g_check_mbr_data[440] = {
55 0xEB, 0x63, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFA, 0x90, 0x90, 0xF6, 0xC2, 0x80, 0x74, 0x05, 0xF6, 0xC2, 0x70,
62 0x74, 0x02, 0xB2, 0x80, 0xEA, 0x79, 0x7C, 0x00, 0x00, 0x31, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC,
63 0x00, 0x20, 0xFB, 0xA0, 0x64, 0x7C, 0x3C, 0xFF, 0x74, 0x02, 0x88, 0xC2, 0x52, 0xBE, 0x90, 0x7D,
64 0xE8, 0x16, 0x01, 0xBE, 0x05, 0x7C, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0xCD, 0x13, 0x5A, 0x52, 0x72,
65 0x3D, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x37, 0x83, 0xE1, 0x01, 0x74, 0x32, 0x31, 0xC0, 0x89, 0x44,
66 0x04, 0x40, 0x88, 0x44, 0xFF, 0x89, 0x44, 0x02, 0xC7, 0x04, 0x10, 0x00, 0x66, 0x8B, 0x1E, 0x5C,
67 0x7C, 0x66, 0x89, 0x5C, 0x08, 0x66, 0x8B, 0x1E, 0x60, 0x7C, 0x66, 0x89, 0x5C, 0x0C, 0xC7, 0x44,
68 0x06, 0x00, 0x70, 0xB4, 0x42, 0xCD, 0x13, 0x72, 0x05, 0xBB, 0x00, 0x70, 0xEB, 0x76, 0xB4, 0x08,
69 0xCD, 0x13, 0x73, 0x0D, 0x5A, 0x84, 0xD2, 0x0F, 0x83, 0xD8, 0x00, 0xBE, 0x96, 0x7D, 0xE9, 0x82,
70 0x00, 0x66, 0x0F, 0xB6, 0xC6, 0x88, 0x64, 0xFF, 0x40, 0x66, 0x89, 0x44, 0x04, 0x0F, 0xB6, 0xD1,
71 0xC1, 0xE2, 0x02, 0x88, 0xE8, 0x88, 0xF4, 0x40, 0x89, 0x44, 0x08, 0x0F, 0xB6, 0xC2, 0xC0, 0xE8,
72 0x02, 0x66, 0x89, 0x04, 0x66, 0xA1, 0x60, 0x7C, 0x66, 0x09, 0xC0, 0x75, 0x4E, 0x66, 0xA1, 0x5C,
73 0x7C, 0x66, 0x31, 0xD2, 0x66, 0xF7, 0x34, 0x88, 0xD1, 0x31, 0xD2, 0x66, 0xF7, 0x74, 0x04, 0x3B,
74 0x44, 0x08, 0x7D, 0x37, 0xFE, 0xC1, 0x88, 0xC5, 0x30, 0xC0, 0xC1, 0xE8, 0x02, 0x08, 0xC1, 0x88,
75 0xD0, 0x5A, 0x88, 0xC6, 0xBB, 0x00, 0x70, 0x8E, 0xC3, 0x31, 0xDB, 0xB8, 0x01, 0x02, 0xCD, 0x13,
76 0x72, 0x1E, 0x8C, 0xC3, 0x60, 0x1E, 0xB9, 0x00, 0x01, 0x8E, 0xDB, 0x31, 0xF6, 0xBF, 0x00, 0x80,
77 0x8E, 0xC6, 0xFC, 0xF3, 0xA5, 0x1F, 0x61, 0xFF, 0x26, 0x5A, 0x7C, 0xBE, 0x93, 0x7D, 0xEB, 0x03,
78 0xBE, 0x99, 0x7D, 0xE8, 0x33, 0x00, 0xBE, 0x9C, 0x7D, 0xE8, 0x2D, 0x00, 0xCD, 0x18, 0xEB, 0xFE,
79 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
80 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44, 0x00, 0x52, 0x64, 0x00, 0x20, 0x45, 0x72, 0x0D,
81 0x0A, 0x00, 0xBB, 0x01, 0x00, 0xB4, 0x0E, 0xCD, 0x10, 0xAC, 0x3C, 0x00, 0x75, 0xF4, 0xC3, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
83 };
84
85 initrd_info *g_initrd_img_list = NULL;
86 initrd_info *g_initrd_img_tail = NULL;
87 int g_initrd_img_count = 0;
88 int g_valid_initrd_count = 0;
89 int g_default_menu_mode = 0;
90 int g_filt_dot_underscore_file = 0;
91 int g_sort_case_sensitive = 0;
92 int g_tree_view_menu_style = 0;
93 static grub_file_t g_old_file;
94 static int g_ventoy_last_entry_back;
95
96 char g_iso_path[256];
97 char g_img_swap_tmp_buf[1024];
98 img_info g_img_swap_tmp;
99 img_info *g_ventoy_img_list = NULL;
100
101 int g_ventoy_img_count = 0;
102
103 grub_device_t g_enum_dev = NULL;
104 grub_fs_t g_enum_fs = NULL;
105 int g_img_max_search_level = -1;
106 img_iterator_node g_img_iterator_head;
107 img_iterator_node *g_img_iterator_tail = NULL;
108
109 grub_uint8_t g_ventoy_break_level = 0;
110 grub_uint8_t g_ventoy_debug_level = 0;
111 grub_uint8_t g_ventoy_chain_type = 0;
112
113 grub_uint8_t *g_ventoy_cpio_buf = NULL;
114 grub_uint32_t g_ventoy_cpio_size = 0;
115 cpio_newc_header *g_ventoy_initrd_head = NULL;
116 grub_uint8_t *g_ventoy_runtime_buf = NULL;
117
118 int g_plugin_image_list = 0;
119
120 ventoy_grub_param *g_grub_param = NULL;
121
122 ventoy_guid g_ventoy_guid = VENTOY_GUID;
123
124 ventoy_img_chunk_list g_img_chunk_list;
125
126 int g_wimboot_enable = 0;
127 ventoy_img_chunk_list g_wimiso_chunk_list;
128 char *g_wimiso_path = NULL;
129
130 int g_vhdboot_enable = 0;
131
132 grub_uint64_t g_conf_replace_offset = 0;
133 grub_uint64_t g_svd_replace_offset = 0;
134 conf_replace *g_conf_replace_node = NULL;
135 grub_uint8_t *g_conf_replace_new_buf = NULL;
136 int g_conf_replace_new_len = 0;
137 int g_conf_replace_new_len_align = 0;
138
139 ventoy_gpt_info *g_ventoy_part_info = NULL;
140 grub_uint64_t g_ventoy_disk_size = 0;
141 grub_uint64_t g_ventoy_disk_part_size[2];
142
143 static char *g_tree_script_buf = NULL;
144 static int g_tree_script_pos = 0;
145
146 static char *g_list_script_buf = NULL;
147 static int g_list_script_pos = 0;
148
149 static char *g_part_list_buf = NULL;
150 static int g_part_list_pos = 0;
151
152 static int g_video_mode_max = 0;
153 static int g_video_mode_num = 0;
154 static ventoy_video_mode *g_video_mode_list = NULL;
155
156 static int g_enumerate_time_checked = 0;
157 static grub_uint64_t g_enumerate_start_time_ms;
158 static grub_uint64_t g_enumerate_finish_time_ms;
159 static int g_vtoy_file_flt[VTOY_FILE_FLT_BUTT] = {0};
160
161 static int g_pager_flag = 0;
162 static char g_old_pager[32];
163
164 static const char *g_vtoy_winpeshl_ini = "[LaunchApps]\r\nvtoyjump.exe";
165
166 static const char *g_menu_class[] =
167 {
168 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
169 };
170
171 const char *g_menu_prefix[img_type_max] =
172 {
173 "iso", "wim", "efi", "img", "vhd", "vtoy"
174 };
175
176 static int g_vtoy_load_prompt = 0;
177 static char g_vtoy_prompt_msg[64];
178
179 static char g_json_case_mis_path[32];
180
181 static int ventoy_get_fs_type(const char *fs)
182 {
183 if (NULL == fs)
184 {
185 return ventoy_fs_max;
186 }
187 else if (grub_strncmp(fs, "exfat", 5) == 0)
188 {
189 return ventoy_fs_exfat;
190 }
191 else if (grub_strncmp(fs, "ntfs", 4) == 0)
192 {
193 return ventoy_fs_ntfs;
194 }
195 else if (grub_strncmp(fs, "ext", 3) == 0)
196 {
197 return ventoy_fs_ext;
198 }
199 else if (grub_strncmp(fs, "xfs", 3) == 0)
200 {
201 return ventoy_fs_xfs;
202 }
203 else if (grub_strncmp(fs, "udf", 3) == 0)
204 {
205 return ventoy_fs_udf;
206 }
207 else if (grub_strncmp(fs, "fat", 3) == 0)
208 {
209 return ventoy_fs_fat;
210 }
211
212 return ventoy_fs_max;
213 }
214
215 static int ventoy_string_check(const char *str, grub_char_check_func check)
216 {
217 if (!str)
218 {
219 return 0;
220 }
221
222 for ( ; *str; str++)
223 {
224 if (!check(*str))
225 {
226 return 0;
227 }
228 }
229
230 return 1;
231 }
232
233
234 static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len)
235 {
236 grub_memcpy(buf, (char *)file->data + file->offset, len);
237 return len;
238 }
239
240 static int ventoy_control_get_flag(const char *key)
241 {
242 const char *val = ventoy_get_env(key);
243
244 if (val && val[0] == '1' && val[1] == 0)
245 {
246 return 1;
247 }
248 return 0;
249 }
250
251 static grub_err_t ventoy_fs_close(grub_file_t file)
252 {
253 grub_file_close(g_old_file);
254 grub_free(file->data);
255
256 file->device = 0;
257 file->name = 0;
258
259 return 0;
260 }
261
262 static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg)
263 {
264 int i;
265
266 (void)hook_arg;
267
268 if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
269 {
270 return 0;
271 }
272
273 for (i = 0; i < g_video_mode_num; i++)
274 {
275 if (g_video_mode_list[i].width == info->width &&
276 g_video_mode_list[i].height == info->height &&
277 g_video_mode_list[i].bpp == info->bpp)
278 {
279 return 0;
280 }
281 }
282
283 g_video_mode_list[g_video_mode_num].width = info->width;
284 g_video_mode_list[g_video_mode_num].height = info->height;
285 g_video_mode_list[g_video_mode_num].bpp = info->bpp;
286 g_video_mode_num++;
287
288 if (g_video_mode_num == g_video_mode_max)
289 {
290 g_video_mode_max *= 2;
291 g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode));
292 }
293
294 return 0;
295 }
296
297 static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2)
298 {
299 if (v1->bpp == v2->bpp)
300 {
301 if (v1->width == v2->width)
302 {
303 if (v1->height == v2->height)
304 {
305 return 0;
306 }
307 else
308 {
309 return (v1->height < v2->height) ? -1 : 1;
310 }
311 }
312 else
313 {
314 return (v1->width < v2->width) ? -1 : 1;
315 }
316 }
317 else
318 {
319 return (v1->bpp < v2->bpp) ? -1 : 1;
320 }
321 }
322
323 static int ventoy_enum_video_mode(void)
324 {
325 int i, j;
326 grub_video_adapter_t adapter;
327 grub_video_driver_id_t id;
328 ventoy_video_mode mode;
329
330 g_video_mode_num = 0;
331 g_video_mode_max = 1024;
332 g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max);
333 if (!g_video_mode_list)
334 {
335 return 0;
336 }
337
338 #ifdef GRUB_MACHINE_PCBIOS
339 grub_dl_load ("vbe");
340 #endif
341
342 id = grub_video_get_driver_id ();
343
344 FOR_VIDEO_ADAPTERS (adapter)
345 {
346 if (!adapter->iterate ||
347 (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE ||
348 adapter->init() != GRUB_ERR_NONE)))
349 {
350 continue;
351 }
352
353 adapter->iterate(ventoy_video_hook, NULL);
354
355 if (adapter->id != id)
356 {
357 adapter->fini();
358 }
359 }
360
361 /* sort video mode */
362 for (i = 0; i < g_video_mode_num; i++)
363 for (j = i + 1; j < g_video_mode_num; j++)
364 {
365 if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0)
366 {
367 grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode));
368 grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode));
369 grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode));
370 }
371 }
372
373 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
374 }
375
376 static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type)
377 {
378 int len;
379 grub_file_t file;
380 static struct grub_fs vtoy_fs =
381 {
382 .name = "vtoy",
383 .fs_dir = 0,
384 .fs_open = 0,
385 .fs_read = ventoy_fs_read,
386 .fs_close = ventoy_fs_close,
387 .fs_label = 0,
388 .next = 0
389 };
390
391 if (type != 52)
392 {
393 return rawFile;
394 }
395
396 file = (grub_file_t)grub_zalloc(sizeof (*file));
397 if (!file)
398 {
399 return 0;
400 }
401
402 file->data = grub_malloc(rawFile->size + 4096);
403 if (!file->data)
404 {
405 return 0;
406 }
407
408 grub_file_read(rawFile, file->data, rawFile->size);
409 len = ventoy_fill_data(4096, (char *)file->data + rawFile->size);
410
411 g_old_file = rawFile;
412
413 file->size = rawFile->size + len;
414 file->device = rawFile->device;
415 file->fs = &vtoy_fs;
416 file->not_easily_seekable = 1;
417
418 return file;
419 }
420
421 static int ventoy_check_decimal_var(const char *name, long *value)
422 {
423 const char *value_str = NULL;
424
425 value_str = grub_env_get(name);
426 if (NULL == value_str)
427 {
428 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name);
429 }
430
431 if (!ventoy_is_decimal(value_str))
432 {
433 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str);
434 }
435
436 *value = grub_strtol(value_str, NULL, 10);
437
438 return GRUB_ERR_NONE;
439 }
440
441 grub_uint64_t ventoy_get_vtoy_partsize(int part)
442 {
443 grub_uint64_t sectors;
444
445 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
446 {
447 sectors = g_ventoy_part_info->PartTbl[part].LastLBA + 1 - g_ventoy_part_info->PartTbl[part].StartLBA;
448 }
449 else
450 {
451 sectors = g_ventoy_part_info->MBR.PartTbl[part].SectorCount;
452 }
453
454 return sectors * 512;
455 }
456
457 static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
458 {
459 int len;
460 grub_file_t file;
461 char exec[128];
462 char *data = NULL;
463 grub_uint32_t offset;
464
465 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
466 if (file == NULL)
467 {
468 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
469 return 1;
470 }
471
472 len = (int)file->size;
473
474 data = (char *)grub_malloc(file->size);
475 if (!data)
476 {
477 return 1;
478 }
479
480 grub_file_read(file, data, file->size);
481 grub_file_close(file);
482
483 grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
484 grub_script_execute_sourcecode(exec);
485
486 file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
487 offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
488 grub_file_close(file);
489
490 grub_script_execute_sourcecode("loopback -d efiboot");
491
492 *buf = data;
493 *datalen = len;
494 *direntoff = offset + 2;
495
496 return 0;
497 }
498
499 static int ventoy_set_check_result(int ret)
500 {
501 char buf[32];
502
503 grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF));
504 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf);
505 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
506
507 if (ret)
508 {
509 grub_printf(VTOY_WARNING"\n");
510 grub_printf(VTOY_WARNING"\n");
511 grub_printf(VTOY_WARNING"\n\n\n");
512
513 grub_printf("This is NOT a standard Ventoy device and is NOT supported (%d).\n\n", ret);
514 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
515
516 grub_printf("\n\nWill exit after 10 seconds ...... ");
517 grub_refresh();
518 grub_sleep(10);
519 }
520
521 return ret;
522 }
523
524 static int ventoy_check_official_device(grub_device_t dev)
525 {
526 int workaround = 0;
527 grub_file_t file;
528 grub_uint64_t offset;
529 char devname[64];
530 grub_fs_t fs;
531 grub_uint8_t mbr[512];
532 grub_disk_t disk;
533 grub_device_t dev2;
534 char *label = NULL;
535 struct grub_partition *partition;
536
537 if (dev->disk == NULL || dev->disk->partition == NULL)
538 {
539 return ventoy_set_check_result(1 | 0x1000);
540 }
541
542 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) ||
543 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) ||
544 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
545 {
546 #ifndef GRUB_MACHINE_EFI
547 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name) ||
548 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name) ||
549 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name))
550 {
551 return ventoy_set_check_result(2 | 0x1000);
552 }
553 else
554 {
555 workaround = 1;
556 }
557 #endif
558 }
559
560 /* We must have partition 2 */
561 if (workaround)
562 {
563 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
564 }
565 else
566 {
567 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name);
568 }
569 if (!file)
570 {
571 return ventoy_set_check_result(3 | 0x1000);
572 }
573
574 if (NULL == grub_strstr(file->fs->name, "fat"))
575 {
576 grub_file_close(file);
577 return ventoy_set_check_result(4 | 0x1000);
578 }
579
580 partition = dev->disk->partition;
581 if (partition->number != 0 || partition->start != 2048)
582 {
583 return ventoy_set_check_result(5);
584 }
585
586 if (workaround)
587 {
588 if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
589 {
590 ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl;
591 if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 ||
592 (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536)
593 {
594 grub_file_close(file);
595 return ventoy_set_check_result(6);
596 }
597 }
598 else
599 {
600 ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl;
601 if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount ||
602 PartTbl[1].SectorCount != 65536)
603 {
604 grub_file_close(file);
605 return ventoy_set_check_result(6);
606 }
607 }
608 }
609 else
610 {
611 offset = partition->start + partition->len;
612 partition = file->device->disk->partition;
613 if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start))
614 {
615 grub_file_close(file);
616 return ventoy_set_check_result(7);
617 }
618 }
619
620 grub_file_close(file);
621
622 if (workaround == 0)
623 {
624 grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name);
625 dev2 = grub_device_open(devname);
626 if (!dev2)
627 {
628 return ventoy_set_check_result(8);
629 }
630
631 fs = grub_fs_probe(dev2);
632 if (!fs)
633 {
634 grub_device_close(dev2);
635 return ventoy_set_check_result(9);
636 }
637
638 fs->fs_label(dev2, &label);
639 if ((!label) || grub_strncmp("VTOYEFI", label, 7))
640 {
641 grub_device_close(dev2);
642 return ventoy_set_check_result(10);
643 }
644
645 grub_device_close(dev2);
646 }
647
648 /* MBR check */
649 disk = grub_disk_open(dev->disk->name);
650 if (!disk)
651 {
652 return ventoy_set_check_result(11);
653 }
654
655 grub_memset(mbr, 0, 512);
656 grub_disk_read(disk, 0, 0, 512, mbr);
657 grub_disk_close(disk);
658
659 g_check_mbr_data[92] = mbr[92];
660 g_check_mbr_data[102] = mbr[102];
661 g_check_mbr_data[103] = mbr[103];
662 grub_memcpy(g_check_mbr_data + 0x180, mbr + 0x180, 16);
663 if (grub_memcmp(g_check_mbr_data, mbr, 440))
664 {
665 return ventoy_set_check_result(12);
666 }
667
668 return ventoy_set_check_result(0);
669 }
670
671 static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
672 {
673 if (0 == info->dir)
674 {
675 if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
676 {
677 *((int *)data) = 1;
678 return 0;
679 }
680 }
681
682 return 0;
683 }
684
685 grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
686 {
687 grub_uint64_t size = 0;
688 grub_file_t file;
689 va_list ap;
690 char fullpath[256] = {0};
691
692 va_start (ap, fmt);
693 grub_vsnprintf(fullpath, 255, fmt, ap);
694 va_end (ap);
695
696 file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
697 if (!file)
698 {
699 debug("grub_file_open failed <%s>\n", fullpath);
700 grub_errno = 0;
701 return 0;
702 }
703
704 size = file->size;
705 grub_file_close(file);
706 return size;
707 }
708
709 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
710 {
711 va_list ap;
712 grub_file_t file;
713 char fullpath[256] = {0};
714
715 va_start (ap, fmt);
716 grub_vsnprintf(fullpath, 255, fmt, ap);
717 va_end (ap);
718
719 file = grub_file_open(fullpath, type);
720 if (!file)
721 {
722 debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno);
723 grub_errno = 0;
724 }
725
726 return file;
727 }
728
729 int ventoy_is_file_exist(const char *fmt, ...)
730 {
731 va_list ap;
732 int len;
733 char *pos = NULL;
734 char buf[256] = {0};
735
736 grub_snprintf(buf, sizeof(buf), "%s", "[ -f \"");
737 pos = buf + 6;
738
739 va_start (ap, fmt);
740 len = grub_vsnprintf(pos, 255, fmt, ap);
741 va_end (ap);
742
743 grub_strncpy(pos + len, "\" ]", 3);
744
745 debug("script exec %s\n", buf);
746
747 if (0 == grub_script_execute_sourcecode(buf))
748 {
749 return 1;
750 }
751
752 return 0;
753 }
754
755 int ventoy_is_dir_exist(const char *fmt, ...)
756 {
757 va_list ap;
758 int len;
759 char *pos = NULL;
760 char buf[256] = {0};
761
762 grub_snprintf(buf, sizeof(buf), "%s", "[ -d \"");
763 pos = buf + 6;
764
765 va_start (ap, fmt);
766 len = grub_vsnprintf(pos, 255, fmt, ap);
767 va_end (ap);
768
769 grub_strncpy(pos + len, "\" ]", 3);
770
771 debug("script exec %s\n", buf);
772
773 if (0 == grub_script_execute_sourcecode(buf))
774 {
775 return 1;
776 }
777
778 return 0;
779 }
780
781 int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len)
782 {
783 mz_stream s;
784 grub_uint8_t *outbuf;
785 grub_uint8_t gzHdr[10] =
786 {
787 0x1F, 0x8B, /* magic */
788 8, /* z method */
789 0, /* flags */
790 0,0,0,0, /* mtime */
791 4, /* xfl */
792 3, /* OS */
793 };
794
795 grub_memset(&s, 0, sizeof(mz_stream));
796
797 mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY);
798
799 outbuf = (grub_uint8_t *)mem_out;
800
801 mem_out_len -= sizeof(gzHdr) + 8;
802 grub_memcpy(outbuf, gzHdr, sizeof(gzHdr));
803 outbuf += sizeof(gzHdr);
804
805 s.avail_in = mem_in_len;
806 s.next_in = mem_in;
807
808 s.avail_out = mem_out_len;
809 s.next_out = outbuf;
810
811 mz_deflate(&s, MZ_FINISH);
812
813 mz_deflateEnd(&s);
814
815 outbuf += s.total_out;
816 *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out);
817 *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out);
818
819 return s.total_out + sizeof(gzHdr) + 8;
820 }
821
822
823 #if 0
824 ventoy grub cmds
825 #endif
826
827 static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args)
828 {
829 if (argc != 1)
830 {
831 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name);
832 }
833
834 if (0 == grub_strcmp(args[0], "on"))
835 {
836 g_ventoy_debug = 1;
837 grub_env_set("vtdebug_flag", "debug");
838 }
839 else
840 {
841 g_ventoy_debug = 0;
842 grub_env_set("vtdebug_flag", "");
843 }
844
845 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
846 }
847
848 static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args)
849 {
850 (void)ctxt;
851
852 if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1'))
853 {
854 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name);
855 grub_printf(" level:\r\n");
856 grub_printf(" 01/11: busybox / (+cat log)\r\n");
857 grub_printf(" 02/12: initrd / (+cat log)\r\n");
858 grub_printf(" 03/13: hook / (+cat log)\r\n");
859 grub_printf("\r\n");
860 grub_printf(" debug:\r\n");
861 grub_printf(" 0: debug is off\r\n");
862 grub_printf(" 1: debug is on\r\n");
863 grub_printf("\r\n");
864 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
865 }
866
867 g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16);
868
869 if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0)
870 {
871 g_ventoy_debug_level = 1;
872 }
873
874 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
875 }
876
877 static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
878 {
879 (void)ctxt;
880
881 if (argc != 2)
882 {
883 return 1;
884 }
885
886 return (grub_strstr(args[0], args[1])) ? 0 : 1;
887 }
888
889 static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
890 {
891 char *c0, *c1;
892
893 (void)ctxt;
894
895 if (argc != 2)
896 {
897 return 1;
898 }
899
900 c0 = args[0];
901 c1 = args[1];
902
903 while (*c0 && *c1)
904 {
905 if (*c0 != *c1)
906 {
907 return 1;
908 }
909 c0++;
910 c1++;
911 }
912
913 if (*c1)
914 {
915 return 1;
916 }
917
918 return 0;
919 }
920
921 static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
922 {
923 long value_long = 0;
924 char buf[32];
925
926 if ((argc != 2) || (!ventoy_is_decimal(args[1])))
927 {
928 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name);
929 }
930
931 if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long))
932 {
933 return grub_errno;
934 }
935
936 value_long += grub_strtol(args[1], NULL, 10);
937
938 grub_snprintf(buf, sizeof(buf), "%ld", value_long);
939 grub_env_set(args[0], buf);
940
941 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
942 }
943
944 static grub_err_t ventoy_cmd_mod(grub_extcmd_context_t ctxt, int argc, char **args)
945 {
946 ulonglong value1 = 0;
947 ulonglong value2 = 0;
948 char buf[32];
949
950 if (argc != 3)
951 {
952 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name);
953 }
954
955 value1 = grub_strtoull(args[0], NULL, 10);
956 value2 = grub_strtoull(args[1], NULL, 10);
957
958 grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1)));
959 grub_env_set(args[2], buf);
960
961 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
962 }
963
964 static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
965 {
966 int rc = 1;
967 char buf[32];
968 grub_file_t file;
969
970 (void)ctxt;
971 (void)argc;
972 (void)args;
973
974 if (argc != 2)
975 {
976 return rc;
977 }
978
979 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
980 if (file == NULL)
981 {
982 debug("failed to open file <%s> for udf check\n", args[0]);
983 return 1;
984 }
985
986 grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
987
988 grub_env_set(args[1], buf);
989
990 grub_file_close(file);
991 rc = 0;
992
993 return rc;
994 }
995
996 static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
997 {
998 grub_file_t file;
999
1000 (void)ctxt;
1001 (void)argc;
1002 (void)args;
1003
1004 g_wimboot_enable = 0;
1005 grub_check_free(g_wimiso_path);
1006 grub_check_free(g_wimiso_chunk_list.chunk);
1007
1008 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
1009 if (!file)
1010 {
1011 return 0;
1012 }
1013
1014 grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
1015 g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1016 if (NULL == g_wimiso_chunk_list.chunk)
1017 {
1018 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
1019 }
1020
1021 g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
1022 g_wimiso_chunk_list.cur_chunk = 0;
1023
1024 ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
1025
1026 g_wimboot_enable = 1;
1027 g_wimiso_path = grub_strdup(args[0]);
1028
1029 grub_file_close(file);
1030
1031 return 0;
1032 }
1033
1034 static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
1035 {
1036 int len = 0;
1037 int totlen = 0;
1038 int offset = 0;
1039 grub_file_t file;
1040 char name[32];
1041 char value[32];
1042 char *buf = NULL;
1043 char *data = NULL;
1044 ventoy_iso9660_override *dirent;
1045
1046 (void)ctxt;
1047
1048 if (argc != 2)
1049 {
1050 return 1;
1051 }
1052
1053 totlen = sizeof(ventoy_chain_head);
1054
1055 if (ventoy_load_efiboot_template(&buf, &len, &offset))
1056 {
1057 debug("failed to load efiboot template %d\n", len);
1058 return 1;
1059 }
1060
1061 totlen += len;
1062
1063 debug("efiboot template len:%d offset:%d\n", len, offset);
1064
1065 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
1066 if (file == NULL)
1067 {
1068 debug("failed to open file <%s>\n", args[0]);
1069 return 1;
1070 }
1071
1072 totlen += ventoy_align_2k(file->size);
1073
1074 dirent = (ventoy_iso9660_override *)(buf + offset);
1075 dirent->first_sector = len / 2048;
1076 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
1077 dirent->size = (grub_uint32_t)file->size;
1078 dirent->size_be = grub_swap_bytes32(dirent->size);
1079
1080 debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
1081
1082 #ifdef GRUB_MACHINE_EFI
1083 data = (char *)grub_efi_allocate_iso_buf(totlen);
1084 #else
1085 data = (char *)grub_malloc(totlen);
1086 #endif
1087
1088 ventoy_fill_os_param(file, (ventoy_os_param *)data);
1089
1090 grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
1091 grub_check_free(buf);
1092
1093 grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
1094 grub_file_close(file);
1095
1096 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1097 grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
1098 grub_env_set(name, value);
1099
1100 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1101 grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
1102 grub_env_set(name, value);
1103
1104 return 0;
1105 }
1106
1107 grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args)
1108 {
1109 (void)ctxt;
1110 (void)argc;
1111 (void)args;
1112
1113 g_vtoy_load_prompt = 0;
1114 grub_memset(g_vtoy_prompt_msg, 0, sizeof(g_vtoy_prompt_msg));
1115
1116 if (argc == 2 && args[0][0] == '1')
1117 {
1118 g_vtoy_load_prompt = 1;
1119 grub_snprintf(g_vtoy_prompt_msg, sizeof(g_vtoy_prompt_msg), "%s", args[1]);
1120 }
1121
1122 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1123 }
1124
1125 int ventoy_need_prompt_load_file(void)
1126 {
1127 return g_vtoy_load_prompt;
1128 }
1129
1130 grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size)
1131 {
1132 grub_uint64_t ro = 0;
1133 grub_uint64_t div = 0;
1134 grub_ssize_t left = size;
1135 char *cur = (char *)buf;
1136
1137 grub_printf("\r%s 1%% ", g_vtoy_prompt_msg);
1138 grub_refresh();
1139
1140 while (left >= VTOY_SIZE_2MB)
1141 {
1142 grub_file_read(file, cur, VTOY_SIZE_2MB);
1143 cur += VTOY_SIZE_2MB;
1144 left -= VTOY_SIZE_2MB;
1145
1146 div = grub_divmod64((grub_uint64_t)((size - left) * 100), (grub_uint64_t)size, &ro);
1147 grub_printf("\r%s %d%% ", g_vtoy_prompt_msg, (int)div);
1148 grub_refresh();
1149 }
1150
1151 if (left > 0)
1152 {
1153 grub_file_read(file, cur, left);
1154 }
1155
1156 grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg);
1157 grub_refresh();
1158
1159 return size;
1160 }
1161
1162 static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
1163 {
1164 int rc = 1;
1165 char name[32];
1166 char value[32];
1167 char *buf = NULL;
1168 grub_file_t file;
1169 enum grub_file_type type;
1170
1171 (void)ctxt;
1172 (void)argc;
1173 (void)args;
1174
1175 if (argc != 3)
1176 {
1177 return rc;
1178 }
1179
1180 if (grub_strcmp(args[0], "nodecompress") == 0)
1181 {
1182 type = VENTOY_FILE_TYPE;
1183 }
1184 else
1185 {
1186 type = GRUB_FILE_TYPE_LINUX_INITRD;
1187 }
1188
1189 file = ventoy_grub_file_open(type, "%s", args[1]);
1190 if (file == NULL)
1191 {
1192 debug("failed to open file <%s>\n", args[1]);
1193 return 1;
1194 }
1195
1196 #ifdef GRUB_MACHINE_EFI
1197 buf = (char *)grub_efi_allocate_chain_buf(file->size);
1198 #else
1199 buf = (char *)grub_malloc(file->size);
1200 #endif
1201
1202 if (!buf)
1203 {
1204 grub_file_close(file);
1205 return 1;
1206 }
1207
1208 if (g_vtoy_load_prompt)
1209 {
1210 ventoy_load_file_with_prompt(file, buf, file->size);
1211 }
1212 else
1213 {
1214 grub_file_read(file, buf, file->size);
1215 }
1216
1217 grub_snprintf(name, sizeof(name), "%s_addr", args[2]);
1218 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1219 grub_env_set(name, value);
1220
1221 grub_snprintf(name, sizeof(name), "%s_size", args[2]);
1222 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1223 grub_env_set(name, value);
1224
1225 grub_file_close(file);
1226 rc = 0;
1227
1228 return rc;
1229 }
1230
1231 static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
1232 {
1233 int rc = 1;
1234 int headlen;
1235 char name[32];
1236 char value[32];
1237 char *buf = NULL;
1238 grub_file_t file;
1239
1240 (void)ctxt;
1241 (void)argc;
1242 (void)args;
1243
1244 if (argc != 2)
1245 {
1246 return rc;
1247 }
1248
1249 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1250 if (file == NULL)
1251 {
1252 debug("failed to open file <%s> for udf check\n", args[0]);
1253 return 1;
1254 }
1255
1256 headlen = sizeof(ventoy_chain_head);
1257
1258 #ifdef GRUB_MACHINE_EFI
1259 buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
1260 #else
1261 buf = (char *)grub_malloc(headlen + file->size);
1262 #endif
1263
1264 ventoy_fill_os_param(file, (ventoy_os_param *)buf);
1265
1266 grub_file_read(file, buf + headlen, file->size);
1267
1268 grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
1269 grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
1270 grub_env_set(name, value);
1271
1272 grub_snprintf(name, sizeof(name), "%s_size", args[1]);
1273 grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
1274 grub_env_set(name, value);
1275
1276 grub_file_close(file);
1277 rc = 0;
1278
1279 return rc;
1280 }
1281
1282 static grub_err_t ventoy_cmd_iso9660_is_joliet(grub_extcmd_context_t ctxt, int argc, char **args)
1283 {
1284 (void)ctxt;
1285 (void)argc;
1286 (void)args;
1287
1288 if (grub_iso9660_is_joliet())
1289 {
1290 debug("This time has joliet process\n");
1291 return 0;
1292 }
1293 else
1294 {
1295 return 1;
1296 }
1297 }
1298
1299 static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
1300 {
1301 (void)ctxt;
1302
1303 if (argc != 1)
1304 {
1305 return 1;
1306 }
1307
1308 if (args[0][0] == '1')
1309 {
1310 grub_iso9660_set_nojoliet(1);
1311 }
1312 else
1313 {
1314 grub_iso9660_set_nojoliet(0);
1315 }
1316
1317 return 0;
1318 }
1319
1320 static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
1321 {
1322 int i;
1323 int rc = 1;
1324 grub_file_t file;
1325 grub_uint8_t buf[32];
1326
1327 (void)ctxt;
1328 (void)argc;
1329 (void)args;
1330
1331 if (argc != 1)
1332 {
1333 return rc;
1334 }
1335
1336 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1337 if (file == NULL)
1338 {
1339 debug("failed to open file <%s> for udf check\n", args[0]);
1340 return 1;
1341 }
1342
1343 for (i = 16; i < 32; i++)
1344 {
1345 grub_file_seek(file, i * 2048);
1346 grub_file_read(file, buf, sizeof(buf));
1347 if (buf[0] == 255)
1348 {
1349 break;
1350 }
1351 }
1352
1353 i++;
1354 grub_file_seek(file, i * 2048);
1355 grub_file_read(file, buf, sizeof(buf));
1356
1357 if (grub_memcmp(buf + 1, "BEA01", 5) == 0)
1358 {
1359 i++;
1360 grub_file_seek(file, i * 2048);
1361 grub_file_read(file, buf, sizeof(buf));
1362
1363 if (grub_memcmp(buf + 1, "NSR02", 5) == 0 ||
1364 grub_memcmp(buf + 1, "NSR03", 5) == 0)
1365 {
1366 rc = 0;
1367 }
1368 }
1369
1370 grub_file_close(file);
1371
1372 debug("ISO UDF: %s\n", rc ? "NO" : "YES");
1373
1374 return rc;
1375 }
1376
1377 static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args)
1378 {
1379 long value_long1 = 0;
1380 long value_long2 = 0;
1381
1382 if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2])))
1383 {
1384 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name);
1385 }
1386
1387 value_long1 = grub_strtol(args[0], NULL, 10);
1388 value_long2 = grub_strtol(args[2], NULL, 10);
1389
1390 if (0 == grub_strcmp(args[1], "eq"))
1391 {
1392 grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1393 }
1394 else if (0 == grub_strcmp(args[1], "ne"))
1395 {
1396 grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1397 }
1398 else if (0 == grub_strcmp(args[1], "gt"))
1399 {
1400 grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1401 }
1402 else if (0 == grub_strcmp(args[1], "lt"))
1403 {
1404 grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1405 }
1406 else if (0 == grub_strcmp(args[1], "ge"))
1407 {
1408 grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1409 }
1410 else if (0 == grub_strcmp(args[1], "le"))
1411 {
1412 grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE;
1413 }
1414 else
1415 {
1416 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name);
1417 }
1418
1419 return grub_errno;
1420 }
1421
1422 static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args)
1423 {
1424 char *pos = NULL;
1425 char buf[128] = {0};
1426
1427 if (argc != 2)
1428 {
1429 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name);
1430 }
1431
1432 grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1);
1433 pos = grub_strstr(buf, ",");
1434 if (pos)
1435 {
1436 *pos = 0;
1437 }
1438
1439 grub_env_set(args[1], buf);
1440
1441 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1442 }
1443
1444 static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args)
1445 {
1446 int i;
1447 char buf[256];
1448 grub_disk_t disk;
1449 char *pos = NULL;
1450 const char *files[] = { "ventoy.dat", "VENTOY.DAT" };
1451
1452 (void)ctxt;
1453
1454 if (argc != 1)
1455 {
1456 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name);
1457 }
1458
1459 for (i = 0; i < (int)ARRAY_SIZE(files); i++)
1460 {
1461 grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]);
1462 if (0 == grub_script_execute_sourcecode(buf))
1463 {
1464 debug("file %s exist, ventoy_compatible YES\n", buf);
1465 grub_env_set("ventoy_compatible", "YES");
1466 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1467 }
1468 else
1469 {
1470 debug("file %s NOT exist\n", buf);
1471 }
1472 }
1473
1474 grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]);
1475 pos = grub_strstr(buf, ")");
1476 if (pos)
1477 {
1478 *pos = 0;
1479 }
1480
1481 disk = grub_disk_open(buf);
1482 if (disk)
1483 {
1484 grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf);
1485 grub_disk_close(disk);
1486
1487 g_img_swap_tmp_buf[703] = 0;
1488 for (i = 318; i < 703; i++)
1489 {
1490 if (g_img_swap_tmp_buf[i] == 'V' &&
1491 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN))
1492 {
1493 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i);
1494 grub_env_set("ventoy_compatible", "YES");
1495 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1496 }
1497 }
1498 }
1499 else
1500 {
1501 debug("failed to open disk <%s>\n", buf);
1502 }
1503
1504 grub_env_set("ventoy_compatible", "NO");
1505 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1506 }
1507
1508 int ventoy_cmp_img(img_info *img1, img_info *img2)
1509 {
1510 char *s1, *s2;
1511 int c1 = 0;
1512 int c2 = 0;
1513
1514 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1515 {
1516 return (img1->plugin_list_index - img2->plugin_list_index);
1517 }
1518
1519 for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++)
1520 {
1521 c1 = *s1;
1522 c2 = *s2;
1523
1524 if (0 == g_sort_case_sensitive)
1525 {
1526 if (grub_islower(c1))
1527 {
1528 c1 = c1 - 'a' + 'A';
1529 }
1530
1531 if (grub_islower(c2))
1532 {
1533 c2 = c2 - 'a' + 'A';
1534 }
1535 }
1536
1537 if (c1 != c2)
1538 {
1539 break;
1540 }
1541 }
1542
1543 return (c1 - c2);
1544 }
1545
1546 static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2)
1547 {
1548 char *s1, *s2;
1549 int c1 = 0;
1550 int c2 = 0;
1551
1552 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1553 {
1554 return (node1->plugin_list_index - node2->plugin_list_index);
1555 }
1556
1557 for (s1 = node1->dir, s2 = node2->dir; *s1 && *s2; s1++, s2++)
1558 {
1559 c1 = *s1;
1560 c2 = *s2;
1561
1562 if (0 == g_sort_case_sensitive)
1563 {
1564 if (grub_islower(c1))
1565 {
1566 c1 = c1 - 'a' + 'A';
1567 }
1568
1569 if (grub_islower(c2))
1570 {
1571 c2 = c2 - 'a' + 'A';
1572 }
1573 }
1574
1575 if (c1 != c2)
1576 {
1577 break;
1578 }
1579 }
1580
1581 return (c1 - c2);
1582 }
1583
1584 void ventoy_swap_img(img_info *img1, img_info *img2)
1585 {
1586 grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
1587
1588 grub_memcpy(img1, img2, sizeof(img_info));
1589 img1->next = g_img_swap_tmp.next;
1590 img1->prev = g_img_swap_tmp.prev;
1591
1592 g_img_swap_tmp.next = img2->next;
1593 g_img_swap_tmp.prev = img2->prev;
1594 grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
1595 }
1596
1597 static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
1598 {
1599 (void)namelen;
1600
1601 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1602 {
1603 return 0;
1604 }
1605
1606 return 1;
1607 }
1608
1609 static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
1610 {
1611 //int i = 0;
1612 int type = 0;
1613 int ignore = 0;
1614 int index = 0;
1615 grub_size_t len;
1616 img_info *img;
1617 img_info *tail;
1618 const menu_tip *tip;
1619 img_iterator_node *tmp;
1620 img_iterator_node *new_node;
1621 img_iterator_node *node = (img_iterator_node *)data;
1622
1623 if (g_enumerate_time_checked == 0)
1624 {
1625 g_enumerate_finish_time_ms = grub_get_time_ms();
1626 if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000)
1627 {
1628 grub_cls();
1629 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1630 grub_refresh();
1631 g_enumerate_time_checked = 1;
1632 }
1633 }
1634
1635 len = grub_strlen(filename);
1636
1637 if (info->dir)
1638 {
1639 if (node->level + 1 > g_img_max_search_level)
1640 {
1641 return 0;
1642 }
1643
1644 if ((len == 1 && filename[0] == '.') ||
1645 (len == 2 && filename[0] == '.' && filename[1] == '.'))
1646 {
1647 return 0;
1648 }
1649
1650 if (!ventoy_img_name_valid(filename, len))
1651 {
1652 return 0;
1653 }
1654
1655 if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
1656 {
1657 return 0;
1658 }
1659
1660 if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST)
1661 {
1662 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename);
1663 index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf);
1664 if (index == 0)
1665 {
1666 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1667 return 0;
1668 }
1669 }
1670
1671 new_node = grub_zalloc(sizeof(img_iterator_node));
1672 if (new_node)
1673 {
1674 new_node->level = node->level + 1;
1675 new_node->plugin_list_index = index;
1676 new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
1677
1678 g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
1679 if (ignore)
1680 {
1681 debug("Directory %s ignored...\n", new_node->dir);
1682 grub_free(new_node);
1683 return 0;
1684 }
1685
1686 new_node->tail = node->tail;
1687
1688 new_node->parent = node;
1689 if (!node->firstchild)
1690 {
1691 node->firstchild = new_node;
1692 }
1693
1694 if (g_img_iterator_tail)
1695 {
1696 g_img_iterator_tail->next = new_node;
1697 g_img_iterator_tail = new_node;
1698 }
1699 else
1700 {
1701 g_img_iterator_head.next = new_node;
1702 g_img_iterator_tail = new_node;
1703 }
1704 }
1705 }
1706 else
1707 {
1708 debug("Find a file %s\n", filename);
1709 if (len < 4)
1710 {
1711 return 0;
1712 }
1713
1714 if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso"))
1715 {
1716 type = img_type_iso;
1717 }
1718 else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
1719 {
1720 type = img_type_wim;
1721 }
1722 else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") ||
1723 (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx"))))
1724 {
1725 type = img_type_vhd;
1726 }
1727 #ifdef GRUB_MACHINE_EFI
1728 else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi"))
1729 {
1730 type = img_type_efi;
1731 }
1732 #endif
1733 else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img"))
1734 {
1735 if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0)
1736 {
1737 if (grub_strncmp(filename + 7, "wimboot", 7) == 0 ||
1738 grub_strncmp(filename + 7, "vhdboot", 7) == 0)
1739 {
1740 return 0;
1741 }
1742 }
1743 type = img_type_img;
1744 }
1745 else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy"))
1746 {
1747 type = img_type_vtoy;
1748 }
1749 else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg"))
1750 {
1751 if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.'))
1752 {
1753 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1754 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf);
1755 }
1756 return 0;
1757 }
1758 else
1759 {
1760 return 0;
1761 }
1762
1763 if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
1764 {
1765 return 0;
1766 }
1767
1768 if (g_plugin_image_list)
1769 {
1770 grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename);
1771 index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf);
1772 if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0)
1773 {
1774 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf);
1775 return 0;
1776 }
1777 else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0)
1778 {
1779 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index);
1780 return 0;
1781 }
1782 }
1783
1784 img = grub_zalloc(sizeof(img_info));
1785 if (img)
1786 {
1787 img->type = type;
1788 img->plugin_list_index = index;
1789 grub_snprintf(img->name, sizeof(img->name), "%s", filename);
1790
1791 img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
1792
1793 img->size = info->size;
1794 if (0 == img->size)
1795 {
1796 img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename);
1797 }
1798
1799 if (img->size < VTOY_FILT_MIN_FILE_SIZE)
1800 {
1801 debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
1802 grub_free(img);
1803 return 0;
1804 }
1805
1806 if (g_ventoy_img_list)
1807 {
1808 tail = *(node->tail);
1809 img->prev = tail;
1810 tail->next = img;
1811 }
1812 else
1813 {
1814 g_ventoy_img_list = img;
1815 }
1816
1817 img->id = g_ventoy_img_count;
1818 img->parent = node;
1819 if (node && NULL == node->firstiso)
1820 {
1821 node->firstiso = img;
1822 }
1823
1824 node->isocnt++;
1825 tmp = node->parent;
1826 while (tmp)
1827 {
1828 tmp->isocnt++;
1829 tmp = tmp->parent;
1830 }
1831
1832 *((img_info **)(node->tail)) = img;
1833 g_ventoy_img_count++;
1834
1835 img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path);
1836
1837 tip = ventoy_plugin_get_menu_tip(img->path);
1838 if (tip)
1839 {
1840 img->tip1 = tip->tip1;
1841 img->tip2 = tip->tip2;
1842 }
1843
1844 img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path);
1845 if (!img->class)
1846 {
1847 img->class = g_menu_class[type];
1848 }
1849 img->menu_prefix = g_menu_prefix[type];
1850
1851 if (img_type_iso == type)
1852 {
1853 if (ventoy_plugin_check_memdisk(img->path))
1854 {
1855 img->menu_prefix = "miso";
1856 }
1857 }
1858
1859 debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
1860 }
1861 }
1862
1863 return 0;
1864 }
1865
1866 int ventoy_fill_data(grub_uint32_t buflen, char *buffer)
1867 {
1868 int len = GRUB_UINT_MAX;
1869 const char *value = NULL;
1870 char name[32] = {0};
1871 char plat[32] = {0};
1872 char guidstr[32] = {0};
1873 ventoy_guid guid = VENTOY_GUID;
1874 const char *fmt1 = NULL;
1875 const char *fmt2 = NULL;
1876 const char *fmt3 = NULL;
1877 grub_uint32_t *puint = (grub_uint32_t *)name;
1878 grub_uint32_t *puint2 = (grub_uint32_t *)plat;
1879 const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1880 const char fmtcode[]={
1881 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1882 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1883 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1884 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1885 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1886 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1887 };
1888
1889 grub_memset(name, 0, sizeof(name));
1890 puint[0] = grub_swap_bytes32(0x56454e54);
1891 puint[3] = grub_swap_bytes32(0x4f4e0000);
1892 puint[2] = grub_swap_bytes32(0x45525349);
1893 puint[1] = grub_swap_bytes32(0x4f595f56);
1894 value = ventoy_get_env(name);
1895
1896 grub_memset(name, 0, sizeof(name));
1897 puint[1] = grub_swap_bytes32(0x5f544f50);
1898 puint[0] = grub_swap_bytes32(0x56544c45);
1899 fmt1 = ventoy_get_env(name);
1900 if (!fmt1)
1901 {
1902 fmt1 = fmtdata;
1903 }
1904
1905 grub_memset(name, 0, sizeof(name));
1906 puint[1] = grub_swap_bytes32(0x5f4c4654);
1907 puint[0] = grub_swap_bytes32(0x56544c45);
1908 fmt2 = ventoy_get_env(name);
1909
1910 grub_memset(name, 0, sizeof(name));
1911 puint[1] = grub_swap_bytes32(0x5f434c52);
1912 puint[0] = grub_swap_bytes32(0x56544c45);
1913 fmt3 = ventoy_get_env(name);
1914
1915 grub_memcpy(guidstr, &guid, sizeof(guid));
1916
1917 puint2[0] = grub_swap_bytes32(g_ventoy_plat_data);
1918
1919 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1920 #pragma GCC diagnostic push
1921 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1922 len = grub_snprintf(buffer, buflen, fmtcode,
1923 fmt1 ? fmt1 : fmtdata,
1924 fmt2 ? fmt2 : fmtdata + 4,
1925 value ? value : "", plat, guidstr,
1926 fmt3 ? fmt3 : fmtdata + 6);
1927 #pragma GCC diagnostic pop
1928
1929 grub_memset(name, 0, sizeof(name));
1930 puint[0] = grub_swap_bytes32(0x76746f79);
1931 puint[2] = grub_swap_bytes32(0x656e7365);
1932 puint[1] = grub_swap_bytes32(0x5f6c6963);
1933 ventoy_set_env(name, guidstr);
1934
1935 return len;
1936 }
1937
1938 int ventoy_check_password(const vtoy_password *pwd, int retry)
1939 {
1940 int offset;
1941 char input[256];
1942 grub_uint8_t md5[16];
1943
1944 while (retry--)
1945 {
1946 grub_memset(input, 0, sizeof(input));
1947
1948 grub_printf("Enter password: ");
1949 grub_refresh();
1950
1951 if (pwd->type == VTOY_PASSWORD_TXT)
1952 {
1953 grub_password_get(input, 128);
1954 if (grub_strcmp(pwd->text, input) == 0)
1955 {
1956 return 0;
1957 }
1958 }
1959 else if (pwd->type == VTOY_PASSWORD_MD5)
1960 {
1961 grub_password_get(input, 128);
1962 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1963 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1964 {
1965 return 0;
1966 }
1967 }
1968 else if (pwd->type == VTOY_PASSWORD_SALT_MD5)
1969 {
1970 offset = (int)grub_snprintf(input, 128, "%s", pwd->salt);
1971 grub_password_get(input + offset, 128);
1972
1973 grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input));
1974 if (grub_memcmp(pwd->md5, md5, 16) == 0)
1975 {
1976 return 0;
1977 }
1978 }
1979
1980 grub_printf("Invalid password!\n\n");
1981 grub_refresh();
1982 }
1983
1984 return 1;
1985 }
1986
1987 static img_info * ventoy_get_min_iso(img_iterator_node *node)
1988 {
1989 img_info *minimg = NULL;
1990 img_info *img = (img_info *)(node->firstiso);
1991
1992 while (img && (img_iterator_node *)(img->parent) == node)
1993 {
1994 if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0))
1995 {
1996 minimg = img;
1997 }
1998 img = img->next;
1999 }
2000
2001 if (minimg)
2002 {
2003 minimg->select = 1;
2004 }
2005
2006 return minimg;
2007 }
2008
2009 static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
2010 {
2011 img_iterator_node *Minchild = NULL;
2012 img_iterator_node *child = node->firstchild;
2013
2014 while (child && child->parent == node)
2015 {
2016 if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0))
2017 {
2018 Minchild = child;
2019 }
2020 child = child->next;
2021 }
2022
2023 if (Minchild)
2024 {
2025 Minchild->select = 1;
2026 }
2027
2028 return Minchild;
2029 }
2030
2031 static int ventoy_dynamic_tree_menu(img_iterator_node *node)
2032 {
2033 int offset = 1;
2034 img_info *img = NULL;
2035 const char *dir_class = NULL;
2036 const char *dir_alias = NULL;
2037 img_iterator_node *child = NULL;
2038
2039 if (node->isocnt == 0 || node->done == 1)
2040 {
2041 return 0;
2042 }
2043
2044 if (node->parent && node->parent->dirlen < node->dirlen)
2045 {
2046 offset = node->parent->dirlen;
2047 }
2048
2049 if (node == &g_img_iterator_head)
2050 {
2051 if (g_default_menu_mode == 0)
2052 {
2053 if (g_tree_view_menu_style == 0)
2054 {
2055 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2056 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2057 " echo 'return ...' \n"
2058 "}\n", "<--");
2059 }
2060 else
2061 {
2062 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2063 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2064 " echo '%s ...' \n"
2065 "}\n", "return");
2066 }
2067 }
2068 }
2069 else
2070 {
2071 node->dir[node->dirlen - 1] = 0;
2072 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2073 if (!dir_class)
2074 {
2075 dir_class = "vtoydir";
2076 }
2077
2078 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2079 if (dir_alias)
2080 {
2081 if (g_tree_view_menu_style == 0)
2082 {
2083 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2084 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2085 "DIR", dir_alias, dir_class, node->dir + offset);
2086 }
2087 else
2088 {
2089 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2090 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2091 dir_alias, dir_class, node->dir + offset);
2092 }
2093 }
2094 else
2095 {
2096 dir_alias = node->dir + offset;
2097
2098 if (g_tree_view_menu_style == 0)
2099 {
2100 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2101 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2102 "DIR", dir_alias, dir_class, node->dir + offset);
2103 }
2104 else
2105 {
2106 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2107 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2108 dir_alias, dir_class, node->dir + offset);
2109 }
2110 }
2111
2112 if (g_tree_view_menu_style == 0)
2113 {
2114 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2115 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
2116 " echo 'return ...' \n"
2117 "}\n", "<--");
2118 }
2119 else
2120 {
2121 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2122 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
2123 " echo '%s ...' \n"
2124 "}\n", "return");
2125 }
2126 }
2127
2128 while ((child = ventoy_get_min_child(node)) != NULL)
2129 {
2130 ventoy_dynamic_tree_menu(child);
2131 }
2132
2133 while ((img = ventoy_get_min_iso(node)) != NULL)
2134 {
2135 if (g_tree_view_menu_style == 0)
2136 {
2137 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2138 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2139 " %s_%s \n"
2140 "}\n",
2141 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2142 img->unsupport ? "[***********] " : "",
2143 img->alias ? img->alias : img->name, img->class, img,
2144 img->menu_prefix,
2145 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2146 }
2147 else
2148 {
2149 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2150 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2151 " %s_%s \n"
2152 "}\n",
2153 img->unsupport ? "[***********] " : "",
2154 img->alias ? img->alias : img->name, img->class, img,
2155 img->menu_prefix,
2156 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2157 }
2158 }
2159
2160 if (node != &g_img_iterator_head)
2161 {
2162 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
2163 }
2164
2165 node->done = 1;
2166 return 0;
2167 }
2168
2169 static int ventoy_set_default_menu(void)
2170 {
2171 int img_len = 0;
2172 char *pos = NULL;
2173 char *end = NULL;
2174 char *def = NULL;
2175 const char *strdata = NULL;
2176 img_info *cur = NULL;
2177 img_info *default_node = NULL;
2178 const char *default_image = NULL;
2179
2180 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2181 if (default_image && default_image[0] == '/')
2182 {
2183 img_len = grub_strlen(default_image);
2184
2185 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2186 {
2187 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2188 {
2189 default_node = cur;
2190 break;
2191 }
2192 }
2193
2194 if (!default_node)
2195 {
2196 return 1;
2197 }
2198
2199 if (0 == g_default_menu_mode)
2200 {
2201 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2202 }
2203 else
2204 {
2205 def = grub_strdup(default_image);
2206 if (!def)
2207 {
2208 return 1;
2209 }
2210
2211 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2212
2213 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2214 if (strdata && strdata[0] == '/')
2215 {
2216 pos = def + grub_strlen(strdata);
2217 if (*pos == '/')
2218 {
2219 pos++;
2220 }
2221 }
2222 else
2223 {
2224 pos = def + 1;
2225 }
2226
2227 while ((end = grub_strchr(pos, '/')) != NULL)
2228 {
2229 *end = 0;
2230 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2231 pos = end + 1;
2232 }
2233
2234 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2235 grub_free(def);
2236 }
2237 }
2238
2239 return 0;
2240 }
2241
2242 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2243 {
2244 img_info *next = NULL;
2245 img_info *cur = g_ventoy_img_list;
2246
2247 (void)ctxt;
2248 (void)argc;
2249 (void)args;
2250
2251 while (cur)
2252 {
2253 next = cur->next;
2254 grub_free(cur);
2255 cur = next;
2256 }
2257
2258 g_ventoy_img_list = NULL;
2259 g_ventoy_img_count = 0;
2260
2261 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2262 }
2263
2264 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2265 {
2266 long img_id = 0;
2267 img_info *cur = g_ventoy_img_list;
2268
2269 (void)ctxt;
2270
2271 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2272 {
2273 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2274 }
2275
2276 img_id = grub_strtol(args[0], NULL, 10);
2277 if (img_id >= g_ventoy_img_count)
2278 {
2279 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2280 }
2281
2282 debug("Find image %ld name \n", img_id);
2283
2284 while (cur && img_id > 0)
2285 {
2286 img_id--;
2287 cur = cur->next;
2288 }
2289
2290 if (!cur)
2291 {
2292 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2293 }
2294
2295 debug("image name is %s\n", cur->name);
2296
2297 grub_env_set(args[1], cur->name);
2298
2299 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2300 }
2301
2302 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2303 {
2304 int len = 0;
2305 char id[32] = {0};
2306 img_info *cur = g_ventoy_img_list;
2307
2308 (void)ctxt;
2309
2310 if (argc != 1)
2311 {
2312 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2313 }
2314
2315 len = (int)grub_strlen(args[0]);
2316
2317 while (cur)
2318 {
2319 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2320 {
2321 break;
2322 }
2323 cur = cur->next;
2324 }
2325
2326 if (!cur)
2327 {
2328 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2329 }
2330
2331 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2332 grub_env_set("chosen", id);
2333 grub_env_export("chosen");
2334
2335 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2336 }
2337
2338 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2339 {
2340 char value[32];
2341 char *pos = NULL;
2342 const char *id = NULL;
2343 img_info *cur = NULL;
2344
2345 (void)ctxt;
2346
2347 if (argc < 1 || argc > 2)
2348 {
2349 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2350 }
2351
2352 id = grub_env_get("chosen");
2353
2354 pos = grub_strstr(id, "VID_");
2355 if (pos)
2356 {
2357 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2358 }
2359 else
2360 {
2361 cur = g_ventoy_img_list;
2362 }
2363
2364 if (!cur)
2365 {
2366 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2367 }
2368
2369 grub_env_set(args[0], cur->path);
2370
2371 if (argc > 1)
2372 {
2373 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2374 grub_env_set(args[1], value);
2375 }
2376
2377 g_svd_replace_offset = 0;
2378
2379 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2380 }
2381
2382
2383 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2384 {
2385 int len;
2386 grub_fs_t fs;
2387 grub_device_t dev = NULL;
2388 img_info *cur = NULL;
2389 img_info *tail = NULL;
2390 img_info *min = NULL;
2391 img_info *head = NULL;
2392 const char *strdata = NULL;
2393 char *device_name = NULL;
2394 char buf[32];
2395 img_iterator_node *node = NULL;
2396 img_iterator_node *tmp = NULL;
2397
2398 (void)ctxt;
2399
2400 if (argc != 2)
2401 {
2402 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2403 }
2404
2405 if (g_ventoy_img_list || g_ventoy_img_count)
2406 {
2407 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2408 }
2409
2410 VTOY_CMD_CHECK(1);
2411
2412 g_enumerate_time_checked = 0;
2413 g_enumerate_start_time_ms = grub_get_time_ms();
2414
2415 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2416 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2417 {
2418 g_filt_dot_underscore_file = 1;
2419 }
2420
2421 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2422 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2423 {
2424 g_sort_case_sensitive = 1;
2425 }
2426
2427 device_name = grub_file_get_device_name(args[0]);
2428 if (!device_name)
2429 {
2430 goto fail;
2431 }
2432
2433 g_enum_dev = dev = grub_device_open(device_name);
2434 if (!dev)
2435 {
2436 goto fail;
2437 }
2438
2439 g_enum_fs = fs = grub_fs_probe(dev);
2440 if (!fs)
2441 {
2442 goto fail;
2443 }
2444
2445 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2446 {
2447 debug("unsupported fs:<%s>\n", fs->name);
2448 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2449 goto fail;
2450 }
2451
2452 ventoy_set_env("vtoy_iso_fs", fs->name);
2453
2454 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2455 if (strdata && strdata[0] == '1')
2456 {
2457 g_default_menu_mode = 1;
2458 }
2459
2460 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2461
2462 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2463
2464 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2465 if (strdata && strdata[0] == '/')
2466 {
2467 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2468 if (g_img_iterator_head.dir[len - 1] != '/')
2469 {
2470 g_img_iterator_head.dir[len++] = '/';
2471 }
2472 g_img_iterator_head.dirlen = len;
2473 }
2474 else
2475 {
2476 g_img_iterator_head.dirlen = 1;
2477 grub_strcpy(g_img_iterator_head.dir, "/");
2478 }
2479
2480 g_img_iterator_head.tail = &tail;
2481
2482 if (g_img_max_search_level < 0)
2483 {
2484 g_img_max_search_level = GRUB_INT_MAX;
2485 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2486 if (strdata && ventoy_is_decimal(strdata))
2487 {
2488 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2489 }
2490 }
2491
2492 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2493 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2494 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2495 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2496 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2497 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2498
2499 for (node = &g_img_iterator_head; node; node = node->next)
2500 {
2501 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2502 }
2503
2504 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2505 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2506 {
2507 g_tree_view_menu_style = 1;
2508 }
2509
2510 ventoy_set_default_menu();
2511
2512 for (node = &g_img_iterator_head; node; node = node->next)
2513 {
2514 ventoy_dynamic_tree_menu(node);
2515 }
2516
2517 /* free node */
2518 node = g_img_iterator_head.next;
2519 while (node)
2520 {
2521 tmp = node->next;
2522 grub_free(node);
2523 node = tmp;
2524 }
2525
2526 /* sort image list by image name */
2527 while (g_ventoy_img_list)
2528 {
2529 min = g_ventoy_img_list;
2530 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2531 {
2532 if (ventoy_cmp_img(min, cur) > 0)
2533 {
2534 min = cur;
2535 }
2536 }
2537
2538 if (min->prev)
2539 {
2540 min->prev->next = min->next;
2541 }
2542
2543 if (min->next)
2544 {
2545 min->next->prev = min->prev;
2546 }
2547
2548 if (min == g_ventoy_img_list)
2549 {
2550 g_ventoy_img_list = min->next;
2551 }
2552
2553 if (head == NULL)
2554 {
2555 head = tail = min;
2556 min->prev = NULL;
2557 min->next = NULL;
2558 }
2559 else
2560 {
2561 tail->next = min;
2562 min->prev = tail;
2563 min->next = NULL;
2564 tail = min;
2565 }
2566 }
2567
2568 g_ventoy_img_list = head;
2569
2570 if (g_default_menu_mode == 1)
2571 {
2572 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2573 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2574 " echo 'return ...' \n"
2575 "}\n", "<--");
2576 }
2577
2578 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2579 {
2580 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2581 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2582 " %s_%s \n"
2583 "}\n",
2584 cur->unsupport ? "[***********] " : "",
2585 cur->alias ? cur->alias : cur->name, cur->class, cur,
2586 cur->menu_prefix,
2587 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2588 }
2589
2590 g_tree_script_buf[g_tree_script_pos] = 0;
2591 g_list_script_buf[g_list_script_pos] = 0;
2592
2593 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2594 grub_env_set(args[1], buf);
2595
2596 fail:
2597
2598 check_free(device_name, grub_free);
2599 check_free(dev, grub_device_close);
2600
2601 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2602 }
2603
2604 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2605 {
2606 grub_disk_t disk;
2607 char *device_name;
2608 char *pos;
2609 char *pos2;
2610
2611 device_name = grub_file_get_device_name(filename);
2612 if (!device_name)
2613 {
2614 return 1;
2615 }
2616
2617 pos = device_name;
2618 if (pos[0] == '(')
2619 {
2620 pos++;
2621 }
2622
2623 pos2 = grub_strstr(pos, ",");
2624 if (!pos2)
2625 {
2626 pos2 = grub_strstr(pos, ")");
2627 }
2628
2629 if (pos2)
2630 {
2631 *pos2 = 0;
2632 }
2633
2634 disk = grub_disk_open(pos);
2635 if (disk)
2636 {
2637 grub_disk_read(disk, 0, 0x180, 16, guid);
2638 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2639 grub_disk_close(disk);
2640 }
2641 else
2642 {
2643 return 1;
2644 }
2645
2646 grub_free(device_name);
2647 return 0;
2648 }
2649
2650 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2651 {
2652 eltorito_descriptor desc;
2653
2654 grub_memset(&desc, 0, sizeof(desc));
2655 grub_file_seek(file, 17 * 2048);
2656 grub_file_read(file, &desc, sizeof(desc));
2657
2658 if (desc.type != 0 || desc.version != 1)
2659 {
2660 return 0;
2661 }
2662
2663 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2664 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2665 {
2666 return 0;
2667 }
2668
2669 return desc.sector;
2670 }
2671
2672 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2673 {
2674 int i;
2675 int x86count = 0;
2676 grub_uint8_t buf[512];
2677 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2678
2679 grub_file_seek(file, sector * 2048);
2680 grub_file_read(file, buf, sizeof(buf));
2681
2682 if (buf[0] == 0x01 && buf[1] == 0xEF)
2683 {
2684 debug("%s efi eltorito in Validation Entry\n", file->name);
2685 return 1;
2686 }
2687
2688 if (buf[0] == 0x01 && buf[1] == 0x00)
2689 {
2690 x86count++;
2691 }
2692
2693 for (i = 64; i < (int)sizeof(buf); i += 32)
2694 {
2695 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2696 {
2697 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2698 return 1;
2699 }
2700
2701 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2702 {
2703 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2704 return 1;
2705 }
2706 }
2707
2708 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2709 {
2710 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2711 {
2712 if (buf[36] == parttype[i])
2713 {
2714 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2715 return 1;
2716 }
2717 }
2718 }
2719
2720 debug("%s does not contain efi eltorito\n", file->name);
2721 return 0;
2722 }
2723
2724 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2725 {
2726 char *pos;
2727 const char *fs = NULL;
2728 const char *cdprompt = NULL;
2729 grub_uint32_t i;
2730 grub_uint8_t chksum = 0;
2731 grub_disk_t disk;
2732
2733 disk = file->device->disk;
2734 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2735
2736 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2737 param->vtoy_disk_part_id = disk->partition->number + 1;
2738 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2739
2740 pos = grub_strstr(file->name, "/");
2741 if (!pos)
2742 {
2743 pos = file->name;
2744 }
2745
2746 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2747
2748 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2749
2750 param->vtoy_img_size = file->size;
2751
2752 param->vtoy_reserved[0] = g_ventoy_break_level;
2753 param->vtoy_reserved[1] = g_ventoy_debug_level;
2754
2755 param->vtoy_reserved[2] = g_ventoy_chain_type;
2756
2757 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2758 param->vtoy_reserved[4] = 0;
2759 if (g_ventoy_chain_type == 1) /* Windows */
2760 {
2761 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2762 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2763 {
2764 param->vtoy_reserved[4] = 1;
2765 }
2766 }
2767
2768 fs = ventoy_get_env("ventoy_fs_probe");
2769 if (fs && grub_strcmp(fs, "udf") == 0)
2770 {
2771 param->vtoy_reserved[3] = 1;
2772 }
2773
2774 /* calculate checksum */
2775 for (i = 0; i < sizeof(ventoy_os_param); i++)
2776 {
2777 chksum += *((grub_uint8_t *)param + i);
2778 }
2779 param->chksum = (grub_uint8_t)(0x100 - chksum);
2780
2781 return;
2782 }
2783
2784 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2785 {
2786 grub_uint32_t i = 0;
2787 grub_uint64_t total = 0;
2788 grub_uint64_t fileblk = 0;
2789 ventoy_img_chunk *chunk = NULL;
2790
2791 for (i = 0; i < chunklist->cur_chunk; i++)
2792 {
2793 chunk = chunklist->chunk + i;
2794
2795 if (chunk->disk_start_sector <= start)
2796 {
2797 debug("%u disk start invalid %lu\n", i, (ulong)start);
2798 return 1;
2799 }
2800
2801 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2802 }
2803
2804 fileblk = (file->size + 511) / 512;
2805
2806 if (total != fileblk)
2807 {
2808 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
2809 if ((file->size % 512) && (total + 1 == fileblk))
2810 {
2811 debug("maybe img file to be processed.\n");
2812 return 0;
2813 }
2814
2815 return 1;
2816 }
2817
2818 return 0;
2819 }
2820
2821 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2822 {
2823 int fs_type;
2824 int len;
2825 grub_uint32_t i = 0;
2826 grub_uint32_t sector = 0;
2827 grub_uint32_t count = 0;
2828 grub_off_t size = 0;
2829 grub_off_t read = 0;
2830
2831 fs_type = ventoy_get_fs_type(file->fs->name);
2832 if (fs_type == ventoy_fs_exfat)
2833 {
2834 grub_fat_get_file_chunk(start, file, chunklist);
2835 }
2836 else if (fs_type == ventoy_fs_ext)
2837 {
2838 grub_ext_get_file_chunk(start, file, chunklist);
2839 }
2840 else
2841 {
2842 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2843 file->read_hook_data = chunklist;
2844
2845 for (size = file->size; size > 0; size -= read)
2846 {
2847 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2848 grub_file_read(file, NULL, read);
2849 }
2850
2851 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2852 {
2853 chunklist->chunk[i].disk_start_sector += start;
2854 chunklist->chunk[i].disk_end_sector += start;
2855 }
2856
2857 if (ventoy_fs_udf == fs_type)
2858 {
2859 for (i = 0; i < chunklist->cur_chunk; i++)
2860 {
2861 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2862 chunklist->chunk[i].img_start_sector = sector;
2863 chunklist->chunk[i].img_end_sector = sector + count - 1;
2864 sector += count;
2865 }
2866 }
2867 }
2868
2869 len = (int)grub_strlen(file->name);
2870 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2871 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2872 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2873 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2874 {
2875 for (i = 0; i < chunklist->cur_chunk; i++)
2876 {
2877 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2878 if (count < 4)
2879 {
2880 count = 1;
2881 }
2882 else
2883 {
2884 count >>= 2;
2885 }
2886
2887 chunklist->chunk[i].img_start_sector = sector;
2888 chunklist->chunk[i].img_end_sector = sector + count - 1;
2889 sector += count;
2890 }
2891 }
2892
2893 return 0;
2894 }
2895
2896 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2897 {
2898 int rc;
2899 grub_file_t file;
2900 grub_disk_addr_t start;
2901
2902 (void)ctxt;
2903 (void)argc;
2904
2905 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2906 if (!file)
2907 {
2908 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2909 }
2910
2911 g_conf_replace_node = NULL;
2912 g_conf_replace_offset = 0;
2913
2914 if (g_img_chunk_list.chunk)
2915 {
2916 grub_free(g_img_chunk_list.chunk);
2917 }
2918
2919 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2920 {
2921 grub_file_close(file);
2922 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2923 }
2924
2925 /* get image chunk data */
2926 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2927 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2928 if (NULL == g_img_chunk_list.chunk)
2929 {
2930 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2931 }
2932
2933 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2934 g_img_chunk_list.cur_chunk = 0;
2935
2936 start = file->device->disk->partition->start;
2937
2938 ventoy_get_block_list(file, &g_img_chunk_list, start);
2939
2940 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2941 grub_file_close(file);
2942
2943 if (rc)
2944 {
2945 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2946 }
2947
2948 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
2949 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2950 }
2951
2952 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
2953 {
2954 grub_uint64_t offset = 0;
2955 grub_uint32_t align = 0;
2956 grub_file_t file = NULL;
2957 conf_replace *node = NULL;
2958
2959 (void)ctxt;
2960 (void)argc;
2961 (void)args;
2962
2963 debug("select conf replace argc:%d\n", argc);
2964
2965 if (argc < 2)
2966 {
2967 return 0;
2968 }
2969
2970 node = ventoy_plugin_find_conf_replace(args[1]);
2971 if (!node)
2972 {
2973 debug("Conf replace not found for %s\n", args[1]);
2974 goto end;
2975 }
2976
2977 debug("Find conf replace for %s\n", args[1]);
2978
2979 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
2980 if (!file)
2981 {
2982 debug("<(loop)%s> NOT exist\n", node->orgconf);
2983 goto end;
2984 }
2985
2986 offset = grub_iso9660_get_last_file_dirent_pos(file);
2987 grub_file_close(file);
2988
2989 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
2990 if (!file)
2991 {
2992 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
2993 goto end;
2994 }
2995
2996 align = ((int)file->size + 2047) / 2048 * 2048;
2997
2998 if (align > vtoy_max_replace_file_size)
2999 {
3000 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3001 goto end;
3002 }
3003
3004 grub_file_read(file, g_conf_replace_new_buf, file->size);
3005 g_conf_replace_new_len = (int)file->size;
3006 g_conf_replace_new_len_align = align;
3007
3008 g_conf_replace_node = node;
3009 g_conf_replace_offset = offset + 2;
3010
3011 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
3012
3013 end:
3014 if (file)
3015 {
3016 grub_file_close(file);
3017 }
3018 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3019 }
3020
3021 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3022 {
3023 int i = 0;
3024 int pos = 0;
3025 int defidx = 1;
3026 char *buf = NULL;
3027 char configfile[128];
3028 install_template *node = NULL;
3029
3030 (void)ctxt;
3031 (void)argc;
3032 (void)args;
3033
3034 debug("select auto installation argc:%d\n", argc);
3035
3036 if (argc < 1)
3037 {
3038 return 0;
3039 }
3040
3041 node = ventoy_plugin_find_install_template(args[0]);
3042 if (!node)
3043 {
3044 debug("Auto install template not found for %s\n", args[0]);
3045 return 0;
3046 }
3047
3048 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3049 {
3050 defidx = node->autosel;
3051 if (node->timeout < 0)
3052 {
3053 node->cursel = node->autosel - 1;
3054 debug("Auto install template auto select %d\n", node->autosel);
3055 return 0;
3056 }
3057 }
3058
3059 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3060 if (!buf)
3061 {
3062 return 0;
3063 }
3064
3065 if (node->timeout > 0)
3066 {
3067 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3068 }
3069
3070 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3071 " echo %s\n}\n", "");
3072
3073 for (i = 0; i < node->templatenum; i++)
3074 {
3075 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\"{\n"
3076 " echo \"\"\n}\n",
3077 node->templatepath[i].path);
3078 }
3079
3080 g_ventoy_menu_esc = 1;
3081 g_ventoy_suppress_esc = 1;
3082 g_ventoy_suppress_esc_default = defidx;
3083
3084 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3085 grub_script_execute_sourcecode(configfile);
3086
3087 g_ventoy_menu_esc = 0;
3088 g_ventoy_suppress_esc = 0;
3089 g_ventoy_suppress_esc_default = 1;
3090
3091 grub_free(buf);
3092
3093 node->cursel = g_ventoy_last_entry - 1;
3094
3095 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3096 }
3097
3098 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3099 {
3100 int i = 0;
3101 int pos = 0;
3102 int defidx = 1;
3103 char *buf = NULL;
3104 char configfile[128];
3105 persistence_config *node;
3106
3107 (void)ctxt;
3108 (void)argc;
3109 (void)args;
3110
3111 debug("select persistence argc:%d\n", argc);
3112
3113 if (argc < 1)
3114 {
3115 return 0;
3116 }
3117
3118 node = ventoy_plugin_find_persistent(args[0]);
3119 if (!node)
3120 {
3121 debug("Persistence image not found for %s\n", args[0]);
3122 return 0;
3123 }
3124
3125 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3126 {
3127 defidx = node->autosel;
3128 if (node->timeout < 0)
3129 {
3130 node->cursel = node->autosel - 1;
3131 debug("Persistence image auto select %d\n", node->autosel);
3132 return 0;
3133 }
3134 }
3135
3136 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3137 if (!buf)
3138 {
3139 return 0;
3140 }
3141
3142 if (node->timeout > 0)
3143 {
3144 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3145 }
3146
3147 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3148 " echo %s\n}\n", "");
3149
3150 for (i = 0; i < node->backendnum; i++)
3151 {
3152 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3153 " echo \"\"\n}\n",
3154 node->backendpath[i].path);
3155
3156 }
3157
3158 g_ventoy_menu_esc = 1;
3159 g_ventoy_suppress_esc = 1;
3160 g_ventoy_suppress_esc_default = defidx;
3161
3162 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3163 grub_script_execute_sourcecode(configfile);
3164
3165 g_ventoy_menu_esc = 0;
3166 g_ventoy_suppress_esc = 0;
3167 g_ventoy_suppress_esc_default = 1;
3168
3169 grub_free(buf);
3170
3171 node->cursel = g_ventoy_last_entry - 1;
3172
3173 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3174 }
3175
3176 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3177 {
3178 grub_uint32_t i;
3179 ventoy_img_chunk *cur;
3180
3181 (void)ctxt;
3182 (void)argc;
3183 (void)args;
3184
3185 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3186 {
3187 cur = g_img_chunk_list.chunk + i;
3188 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3189 cur->img_start_sector, cur->img_end_sector,
3190 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3191 );
3192 }
3193
3194 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3195 }
3196
3197 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3198 {
3199 grub_uint32_t i;
3200 grub_file_t file;
3201 ventoy_img_chunk_list chunklist;
3202
3203 (void)ctxt;
3204 (void)argc;
3205
3206 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3207 if (!file)
3208 {
3209 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3210 }
3211
3212 /* get image chunk data */
3213 grub_memset(&chunklist, 0, sizeof(chunklist));
3214 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3215 if (NULL == chunklist.chunk)
3216 {
3217 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3218 }
3219
3220 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3221 chunklist.cur_chunk = 0;
3222
3223 ventoy_get_block_list(file, &chunklist, 0);
3224
3225 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3226 {
3227 grub_printf("########## UNSUPPORTED ###############\n");
3228 }
3229
3230 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3231
3232 for (i = 0; i < chunklist.cur_chunk; i++)
3233 {
3234 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3235 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3236 }
3237
3238 grub_printf("\n==================================\n");
3239
3240 for (i = 0; i < chunklist.cur_chunk; i++)
3241 {
3242 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3243 (ulonglong)chunklist.chunk[i].img_start_sector,
3244 (ulonglong)chunklist.chunk[i].img_end_sector,
3245 (ulonglong)chunklist.chunk[i].disk_start_sector,
3246 (ulonglong)chunklist.chunk[i].disk_end_sector
3247 );
3248 }
3249
3250 grub_free(chunklist.chunk);
3251 grub_file_close(file);
3252
3253 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3254 }
3255
3256 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3257 {
3258 int i;
3259 ventoy_grub_param_file_replace *replace = NULL;
3260
3261 (void)ctxt;
3262 (void)argc;
3263 (void)args;
3264
3265 if (argc >= 2)
3266 {
3267 replace = &(g_grub_param->file_replace);
3268 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3269
3270 replace->old_name_cnt = 0;
3271 for (i = 0; i < 4 && i + 1 < argc; i++)
3272 {
3273 replace->old_name_cnt++;
3274 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3275 }
3276
3277 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3278 }
3279
3280 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3281 }
3282
3283 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3284 {
3285 char buf[32];
3286 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3287
3288 (void)ctxt;
3289
3290 if (argc >= 1)
3291 {
3292 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3293 grub_env_set(args[0], buf);
3294 }
3295
3296 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3297 }
3298
3299 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3300 {
3301 (void)ctxt;
3302 (void)argc;
3303 (void)args;
3304
3305 if (argc == 0)
3306 {
3307 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3308 grub_printf("%s", g_list_script_buf);
3309 }
3310 else
3311 {
3312 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3313 grub_printf("%s", g_tree_script_buf);
3314 }
3315
3316 return 0;
3317 }
3318
3319 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3320 {
3321 img_info *cur = g_ventoy_img_list;
3322
3323 (void)ctxt;
3324 (void)argc;
3325 (void)args;
3326
3327 while (cur)
3328 {
3329 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3330 grub_printf("name:<%s>\n\n", cur->name);
3331 cur = cur->next;
3332 }
3333
3334 return 0;
3335 }
3336
3337 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3338 {
3339 (void)ctxt;
3340 (void)argc;
3341 (void)args;
3342
3343 ventoy_plugin_dump_injection();
3344
3345 return 0;
3346 }
3347
3348 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3349 {
3350 (void)ctxt;
3351 (void)argc;
3352 (void)args;
3353
3354 ventoy_plugin_dump_auto_install();
3355
3356 return 0;
3357 }
3358
3359 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3360 {
3361 (void)ctxt;
3362 (void)argc;
3363 (void)args;
3364
3365 ventoy_plugin_dump_persistence();
3366
3367 return 0;
3368 }
3369
3370 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3371 {
3372 (void)ctxt;
3373 (void)argc;
3374 (void)args;
3375
3376 if (argc != 1)
3377 {
3378 return 1;
3379 }
3380
3381 if (args[0][0] == '0')
3382 {
3383 return g_ventoy_memdisk_mode ? 0 : 1;
3384 }
3385 else if (args[0][0] == '1')
3386 {
3387 return g_ventoy_iso_raw ? 0 : 1;
3388 }
3389 else if (args[0][0] == '2')
3390 {
3391 return g_ventoy_iso_uefi_drv ? 0 : 1;
3392 }
3393 else if (args[0][0] == '3')
3394 {
3395 return g_ventoy_grub2_mode ? 0 : 1;
3396 }
3397 else if (args[0][0] == '4')
3398 {
3399 return g_ventoy_wimboot_mode ? 0 : 1;
3400 }
3401
3402 return 1;
3403 }
3404
3405 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3406 {
3407 static int configfile_mode = 0;
3408 char memfile[128] = {0};
3409
3410 (void)ctxt;
3411 (void)argc;
3412 (void)args;
3413
3414 /*
3415 * args[0]: 0:normal 1:configfile
3416 * args[1]: 0:list_buf 1:tree_buf
3417 */
3418
3419 if (argc != 2)
3420 {
3421 debug("Invalid argc %d\n", argc);
3422 return 0;
3423 }
3424
3425 VTOY_CMD_CHECK(1);
3426
3427 if (args[0][0] == '0')
3428 {
3429 if (args[1][0] == '0')
3430 {
3431 grub_script_execute_sourcecode(g_list_script_buf);
3432 }
3433 else
3434 {
3435 grub_script_execute_sourcecode(g_tree_script_buf);
3436 }
3437 }
3438 else
3439 {
3440 if (configfile_mode)
3441 {
3442 debug("Now already in F3 mode %d\n", configfile_mode);
3443 return 0;
3444 }
3445
3446 if (args[1][0] == '0')
3447 {
3448 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3449 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3450 }
3451 else
3452 {
3453 g_ventoy_last_entry = -1;
3454 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3455 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3456 }
3457
3458 configfile_mode = 1;
3459 grub_script_execute_sourcecode(memfile);
3460 configfile_mode = 0;
3461 }
3462
3463 return 0;
3464 }
3465
3466 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3467 {
3468 grub_file_t file;
3469
3470 (void)ctxt;
3471
3472 if (argc != 1)
3473 {
3474 return 1;
3475 }
3476
3477 g_ventoy_case_insensitive = 1;
3478 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3479 g_ventoy_case_insensitive = 0;
3480
3481 grub_errno = 0;
3482
3483 if (file)
3484 {
3485 grub_file_close(file);
3486 return 0;
3487 }
3488 return 1;
3489 }
3490
3491 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3492 {
3493 int id = 0;
3494 int find = 0;
3495 grub_disk_t disk;
3496 const char *isopath = NULL;
3497 char hdname[32];
3498 ventoy_mbr_head mbr;
3499
3500 (void)ctxt;
3501 (void)argc;
3502
3503 if (argc != 1)
3504 {
3505 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3506 }
3507
3508 isopath = grub_env_get("vtoy_iso_part");
3509 if (!isopath)
3510 {
3511 debug("isopath is null %p\n", isopath);
3512 return 0;
3513 }
3514
3515 debug("isopath is %s\n", isopath);
3516
3517 for (id = 0; id < 30 && (find == 0); id++)
3518 {
3519 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3520 if (grub_strstr(isopath, hdname))
3521 {
3522 debug("skip %s ...\n", hdname);
3523 continue;
3524 }
3525
3526 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3527
3528 disk = grub_disk_open(hdname);
3529 if (!disk)
3530 {
3531 debug("%s not exist\n", hdname);
3532 break;
3533 }
3534
3535 grub_memset(&mbr, 0, sizeof(mbr));
3536 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3537 {
3538 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3539 {
3540 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3541 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3542 {
3543
3544 grub_env_set(args[0], hdname);
3545 find = 1;
3546 }
3547 }
3548 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3549 }
3550 else
3551 {
3552 debug("read %s failed\n", hdname);
3553 }
3554
3555 grub_disk_close(disk);
3556 }
3557
3558 return 0;
3559 }
3560
3561 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3562 {
3563 int len = 1024;
3564 grub_file_t file;
3565 char *buf = NULL;
3566
3567 (void)ctxt;
3568 (void)argc;
3569
3570 if (argc != 2)
3571 {
3572 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3573 }
3574
3575 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3576 if (!file)
3577 {
3578 debug("failed to open file %s\n", args[0]);
3579 return 0;
3580 }
3581
3582 buf = grub_malloc(len);
3583 if (!buf)
3584 {
3585 goto end;
3586 }
3587
3588 buf[len - 1] = 0;
3589 grub_file_read(file, buf, len - 1);
3590
3591 ventoy_get_line(buf);
3592 ventoy_set_env(args[1], buf);
3593
3594 end:
3595
3596 grub_check_free(buf);
3597 grub_file_close(file);
3598
3599 return 0;
3600 }
3601
3602 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3603 {
3604 int *pCnt = (int *)data;
3605
3606 (void)disk;
3607
3608 (*pCnt)++;
3609 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3610 "0 %llu linear /dev/ventoy %llu\n",
3611 (ulonglong)partition->len, (ulonglong)partition->start);
3612
3613 return 0;
3614 }
3615
3616 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3617 {
3618 int cnt = 0;
3619 char *device_name = NULL;
3620 grub_device_t dev = NULL;
3621 char buf[64];
3622
3623 (void)ctxt;
3624
3625 g_part_list_pos = 0;
3626 grub_env_unset("vtoy_img_part_file");
3627
3628 if (argc != 1)
3629 {
3630 return 1;
3631 }
3632
3633 device_name = grub_file_get_device_name(args[0]);
3634 if (!device_name)
3635 {
3636 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3637 goto end;
3638 }
3639
3640 dev = grub_device_open(device_name);
3641 if (!dev)
3642 {
3643 debug("grub_device_open failed, %s\n", device_name);
3644 goto end;
3645 }
3646
3647 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
3648
3649 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3650 grub_env_set("vtoy_img_part_file", buf);
3651
3652 grub_snprintf(buf, sizeof(buf), "%d", cnt);
3653 grub_env_set("vtoy_img_part_cnt", buf);
3654
3655 end:
3656
3657 check_free(device_name, grub_free);
3658 check_free(dev, grub_device_close);
3659
3660 return 0;
3661 }
3662
3663
3664 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3665 {
3666 int rc = 1;
3667 grub_file_t file;
3668 char *buf = NULL;
3669
3670 (void)ctxt;
3671 (void)argc;
3672
3673 if (argc != 2)
3674 {
3675 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3676 }
3677
3678 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3679 if (!file)
3680 {
3681 debug("failed to open file %s\n", args[0]);
3682 return 1;
3683 }
3684
3685 buf = grub_malloc(file->size + 1);
3686 if (!buf)
3687 {
3688 goto end;
3689 }
3690
3691 buf[file->size] = 0;
3692 grub_file_read(file, buf, file->size);
3693
3694 if (grub_strstr(buf, args[1]))
3695 {
3696 rc = 0;
3697 }
3698
3699 end:
3700
3701 grub_check_free(buf);
3702 grub_file_close(file);
3703
3704 return rc;
3705 }
3706
3707 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3708 {
3709 int len;
3710 grub_file_t file;
3711 char buf[64];
3712 grub_uint64_t size;
3713 ventoy_iso9660_vd pvd;
3714
3715 (void)ctxt;
3716 (void)argc;
3717
3718 if (argc != 4)
3719 {
3720 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3721 }
3722
3723 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3724 if (!file)
3725 {
3726 debug("failed to open file %s\n", args[0]);
3727 return 0;
3728 }
3729
3730 grub_file_seek(file, 16 * 2048);
3731 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3732 if (len != sizeof(pvd))
3733 {
3734 debug("failed to read pvd %d\n", len);
3735 goto end;
3736 }
3737
3738 grub_memset(buf, 0, sizeof(buf));
3739 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3740 ventoy_set_env(args[1], buf);
3741
3742 grub_memset(buf, 0, sizeof(buf));
3743 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3744 ventoy_set_env(args[2], buf);
3745
3746 size = pvd.space;
3747 size *= 2048;
3748 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3749 ventoy_set_env(args[3], buf);
3750
3751 end:
3752 grub_file_close(file);
3753
3754 return 0;
3755 }
3756
3757 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3758 {
3759 int len;
3760 grub_file_t file;
3761 char buf[64];
3762
3763 (void)ctxt;
3764 (void)argc;
3765
3766 if (argc != 2)
3767 {
3768 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3769 }
3770
3771 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3772 if (!file)
3773 {
3774 debug("failed to open file %s\n", args[0]);
3775 return 0;
3776 }
3777
3778 grub_memset(buf, 0, sizeof(buf));
3779 grub_file_seek(file, 16 * 2048 + 813);
3780 len = (int)grub_file_read(file, buf, 17);
3781 if (len != 17)
3782 {
3783 debug("failed to read create date %d\n", len);
3784 goto end;
3785 }
3786
3787 ventoy_set_env(args[1], buf);
3788
3789 end:
3790 grub_file_close(file);
3791
3792 return 0;
3793 }
3794
3795 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3796 {
3797 (void)ctxt;
3798 (void)argc;
3799 (void)args;
3800
3801 ventoy_env_hook_root(1);
3802
3803 return 0;
3804 }
3805
3806 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3807 {
3808 (void)ctxt;
3809 (void)argc;
3810 (void)args;
3811
3812 ventoy_env_hook_root(0);
3813
3814 return 0;
3815 }
3816
3817 #ifdef GRUB_MACHINE_EFI
3818 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3819 {
3820 int ret = 1;
3821 grub_uint8_t *var;
3822 grub_size_t size;
3823 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3824
3825 (void)ctxt;
3826 (void)argc;
3827 (void)args;
3828
3829 var = grub_efi_get_variable("SecureBoot", &global, &size);
3830 if (var && *var == 1)
3831 {
3832 return 0;
3833 }
3834
3835 return ret;
3836 }
3837 #else
3838 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3839 {
3840 (void)ctxt;
3841 (void)argc;
3842 (void)args;
3843 return 1;
3844 }
3845 #endif
3846
3847 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3848 {
3849 int i;
3850 int ret = 1;
3851 grub_file_t file;
3852 grub_uint64_t FileSectors = 0;
3853 ventoy_gpt_info *gpt = NULL;
3854 ventoy_part_table *pt = NULL;
3855 grub_uint8_t zeroguid[16] = {0};
3856
3857 (void)ctxt;
3858 (void)argc;
3859
3860 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3861 if (!file)
3862 {
3863 debug("failed to open file %s\n", args[0]);
3864 return 1;
3865 }
3866
3867 if (file->size % 512)
3868 {
3869 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3870 goto out;
3871 }
3872
3873 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3874 if (!gpt)
3875 {
3876 goto out;
3877 }
3878
3879 FileSectors = file->size / 512;
3880
3881 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3882 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3883 {
3884 debug("This is EFI partition table\n");
3885
3886 for (i = 0; i < 128; i++)
3887 {
3888 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3889 {
3890 if (FileSectors < gpt->PartTbl[i].LastLBA)
3891 {
3892 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3893 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3894 goto out;
3895 }
3896 }
3897 }
3898 }
3899 else
3900 {
3901 debug("This is MBR partition table\n");
3902
3903 for (i = 0; i < 4; i++)
3904 {
3905 pt = gpt->MBR.PartTbl + i;
3906 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3907 {
3908 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3909 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3910 (ulonglong)FileSectors);
3911 goto out;
3912 }
3913 }
3914 }
3915
3916 ret = 0;
3917
3918 out:
3919 grub_file_close(file);
3920 grub_check_free(gpt);
3921 grub_errno = GRUB_ERR_NONE;
3922 return ret;
3923 }
3924
3925 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3926 {
3927 int i;
3928 int ret;
3929
3930 (void)ctxt;
3931 (void)argc;
3932 (void)args;
3933
3934 for (i = 0; i < 500; i++)
3935 {
3936 ret = grub_getkey_noblock();
3937 if (ret == GRUB_TERM_NO_KEY)
3938 {
3939 break;
3940 }
3941 }
3942
3943 if (i >= 500)
3944 {
3945 grub_cls();
3946 grub_printf("\n\n Still have key input after clear.\n");
3947 grub_refresh();
3948 grub_sleep(5);
3949 }
3950
3951 return 0;
3952 }
3953
3954 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
3955 {
3956 int i;
3957 int buflen;
3958 int datalen;
3959 int loclen;
3960 int img_chunk_num;
3961 int image_sector_size;
3962 char cmd[64];
3963 ventoy_chain_head *chain;
3964 ventoy_img_chunk *chunk;
3965 ventoy_os_param *osparam;
3966 ventoy_image_location *location;
3967 ventoy_image_disk_region *region;
3968 struct grub_acpi_table_header *acpi;
3969
3970 (void)ctxt;
3971
3972 if (argc != 2)
3973 {
3974 return 1;
3975 }
3976
3977 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
3978
3979 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
3980 if (!chain)
3981 {
3982 return 1;
3983 }
3984
3985 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
3986
3987 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
3988 {
3989 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
3990 return 1;
3991 }
3992
3993 img_chunk_num = chain->img_chunk_num;
3994
3995 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
3996 datalen = sizeof(ventoy_os_param) + loclen;
3997
3998 buflen = sizeof(struct grub_acpi_table_header) + datalen;
3999 acpi = grub_zalloc(buflen);
4000 if (!acpi)
4001 {
4002 return 1;
4003 }
4004
4005 /* Step1: Fill acpi table header */
4006 grub_memcpy(acpi->signature, "VTOY", 4);
4007 acpi->length = buflen;
4008 acpi->revision = 1;
4009 grub_memcpy(acpi->oemid, "VENTOY", 6);
4010 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4011 acpi->oemrev = 1;
4012 acpi->creator_id[0] = 1;
4013 acpi->creator_rev = 1;
4014
4015 /* Step2: Fill data */
4016 osparam = (ventoy_os_param *)(acpi + 1);
4017 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4018 osparam->vtoy_img_location_addr = 0;
4019 osparam->vtoy_img_location_len = loclen;
4020 osparam->chksum = 0;
4021 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4022
4023 location = (ventoy_image_location *)(osparam + 1);
4024 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4025 location->image_sector_size = image_sector_size;
4026 location->disk_sector_size = chain->disk_sector_size;
4027 location->region_count = img_chunk_num;
4028
4029 region = location->regions;
4030 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4031 if (512 == image_sector_size)
4032 {
4033 for (i = 0; i < img_chunk_num; i++)
4034 {
4035 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4036 region->image_start_sector = chunk->img_start_sector * 4;
4037 region->disk_start_sector = chunk->disk_start_sector;
4038 region++;
4039 chunk++;
4040 }
4041 }
4042 else
4043 {
4044 for (i = 0; i < img_chunk_num; i++)
4045 {
4046 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4047 region->image_start_sector = chunk->img_start_sector;
4048 region->disk_start_sector = chunk->disk_start_sector;
4049 region++;
4050 chunk++;
4051 }
4052 }
4053
4054 /* Step3: Fill acpi checksum */
4055 acpi->checksum = 0;
4056 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4057
4058 /* load acpi table */
4059 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4060 grub_script_execute_sourcecode(cmd);
4061
4062 grub_free(acpi);
4063
4064 VENTOY_CMD_RETURN(0);
4065 }
4066
4067 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4068 {
4069 (void)ctxt;
4070 (void)argc;
4071 (void)args;
4072
4073 g_ventoy_last_entry_back = g_ventoy_last_entry;
4074 g_ventoy_last_entry = -1;
4075
4076 return 0;
4077 }
4078
4079 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4080 {
4081 (void)ctxt;
4082 (void)argc;
4083 (void)args;
4084
4085 g_ventoy_last_entry = g_ventoy_last_entry_back;
4086
4087 return 0;
4088 }
4089
4090 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4091 {
4092 const char *pos = filename + 1;
4093
4094 if (info->dir)
4095 {
4096 while (*pos)
4097 {
4098 if (*pos == '.')
4099 {
4100 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4101 {
4102 grub_strncpy((char *)data, filename, 128);
4103 return 1;
4104 }
4105 }
4106 pos++;
4107 }
4108 }
4109
4110 return 0;
4111 }
4112
4113 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4114 {
4115 int rc = 1;
4116 char *device_name = NULL;
4117 grub_device_t dev = NULL;
4118 grub_fs_t fs = NULL;
4119 char buf[128] = {0};
4120
4121 (void)ctxt;
4122
4123 if (argc != 3)
4124 {
4125 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4126 return 1;
4127 }
4128
4129 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4130
4131 device_name = grub_file_get_device_name(args[0]);
4132 if (!device_name)
4133 {
4134 debug("grub_file_get_device_name failed, %s\n", args[0]);
4135 goto end;
4136 }
4137
4138 dev = grub_device_open(device_name);
4139 if (!dev)
4140 {
4141 debug("grub_device_open failed, %s\n", device_name);
4142 goto end;
4143 }
4144
4145 fs = grub_fs_probe(dev);
4146 if (!fs)
4147 {
4148 debug("grub_fs_probe failed, %s\n", device_name);
4149 goto end;
4150 }
4151
4152 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4153
4154 if (buf[0])
4155 {
4156 ventoy_set_env(args[2], buf);
4157 }
4158
4159 rc = 0;
4160
4161 end:
4162
4163 check_free(device_name, grub_free);
4164 check_free(dev, grub_device_close);
4165
4166 return rc;
4167 }
4168
4169 int ventoy_load_part_table(const char *diskname)
4170 {
4171 char name[64];
4172 int ret;
4173 grub_disk_t disk;
4174 grub_device_t dev;
4175
4176 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4177 if (!g_ventoy_part_info)
4178 {
4179 return 1;
4180 }
4181
4182 disk = grub_disk_open(diskname);
4183 if (!disk)
4184 {
4185 debug("Failed to open disk %s\n", diskname);
4186 return 1;
4187 }
4188
4189 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4190
4191 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4192 grub_disk_close(disk);
4193
4194 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4195 dev = grub_device_open(name);
4196 if (dev)
4197 {
4198 /* Check for official Ventoy device */
4199 ret = ventoy_check_official_device(dev);
4200 grub_device_close(dev);
4201
4202 if (ret)
4203 {
4204 return 1;
4205 }
4206 }
4207
4208 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4209 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4210
4211 return 0;
4212 }
4213
4214 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4215 {
4216 int ret;
4217
4218 (void)argc;
4219 (void)ctxt;
4220
4221 ret = ventoy_load_part_table(args[0]);
4222 if (ret)
4223 {
4224 grub_exit();
4225 }
4226
4227 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4228 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4229
4230 return 0;
4231 }
4232
4233 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4234 {
4235 int ret = 1;
4236 const char *vcfg = NULL;
4237
4238 (void)argc;
4239 (void)ctxt;
4240
4241 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4242 if (vcfg)
4243 {
4244 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4245 grub_env_set(args[1], vcfg);
4246 ret = 0;
4247 }
4248 else
4249 {
4250 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4251 }
4252
4253 grub_errno = 0;
4254 return ret;
4255 }
4256
4257
4258 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4259 {
4260 int id;
4261 grub_uint8_t zeroguid[16] = {0};
4262
4263 (void)argc;
4264 (void)ctxt;
4265
4266 id = (int)grub_strtoul(args[0], NULL, 10);
4267 grub_errno = 0;
4268
4269 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4270 {
4271 if (id >= 1 && id <= 128)
4272 {
4273 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4274 {
4275 return 0;
4276 }
4277 }
4278 }
4279 else
4280 {
4281 if (id >= 1 && id <= 4)
4282 {
4283 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4284 {
4285 return 0;
4286 }
4287 }
4288 }
4289
4290 return 1;
4291 }
4292
4293 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4294 {
4295 int rc = 1;
4296 char *device_name = NULL;
4297 grub_device_t dev = NULL;
4298 grub_fs_t fs = NULL;
4299 char *label = NULL;
4300
4301 (void)ctxt;
4302
4303 debug("get fs label for %s\n", args[0]);
4304
4305 if (argc != 2)
4306 {
4307 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4308 return 1;
4309 }
4310
4311 device_name = grub_file_get_device_name(args[0]);
4312 if (!device_name)
4313 {
4314 debug("grub_file_get_device_name failed, %s\n", args[0]);
4315 goto end;
4316 }
4317
4318 dev = grub_device_open(device_name);
4319 if (!dev)
4320 {
4321 debug("grub_device_open failed, %s\n", device_name);
4322 goto end;
4323 }
4324
4325 fs = grub_fs_probe(dev);
4326 if (NULL == fs || NULL == fs->fs_label)
4327 {
4328 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4329 goto end;
4330 }
4331
4332 fs->fs_label(dev, &label);
4333 if (label)
4334 {
4335 debug("label=<%s>\n", label);
4336 ventoy_set_env(args[1], label);
4337 grub_free(label);
4338 }
4339
4340 rc = 0;
4341
4342 end:
4343
4344 check_free(device_name, grub_free);
4345 check_free(dev, grub_device_close);
4346
4347 return rc;
4348 }
4349
4350 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4351 {
4352 if (!info->dir)
4353 {
4354 grub_snprintf((char *)data, 256, "%s", filename);
4355 return 1;
4356 }
4357
4358 return 0;
4359 }
4360
4361 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4362 {
4363 if (info->dir && filename && filename[0] != '.')
4364 {
4365 grub_snprintf((char *)data, 256, "%s", filename);
4366 return 1;
4367 }
4368
4369 return 0;
4370 }
4371
4372 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4373 {
4374 int rc = 1;
4375 char *device_name = NULL;
4376 grub_device_t dev = NULL;
4377 grub_fs_t fs = NULL;
4378 char name[256] ={0};
4379
4380 if (argc != 3)
4381 {
4382 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4383 return 1;
4384 }
4385
4386 device_name = grub_file_get_device_name(args[0]);
4387 if (!device_name)
4388 {
4389 debug("grub_file_get_device_name failed, %s\n", args[0]);
4390 goto end;
4391 }
4392
4393 dev = grub_device_open(device_name);
4394 if (!dev)
4395 {
4396 debug("grub_device_open failed, %s\n", device_name);
4397 goto end;
4398 }
4399
4400 fs = grub_fs_probe(dev);
4401 if (!fs)
4402 {
4403 debug("grub_fs_probe failed, %s\n", device_name);
4404 goto end;
4405 }
4406
4407 fs->fs_dir(dev, args[1], hook, name);
4408 if (name[0])
4409 {
4410 ventoy_set_env(args[2], name);
4411 }
4412
4413 rc = 0;
4414
4415 end:
4416
4417 check_free(device_name, grub_free);
4418 check_free(dev, grub_device_close);
4419
4420 return rc;
4421 }
4422
4423 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4424 {
4425 (void)ctxt;
4426 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4427 }
4428
4429 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4430 {
4431 (void)ctxt;
4432 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4433 }
4434
4435 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4436 {
4437 char c;
4438 char *pos = NULL;
4439 char *end = NULL;
4440
4441 (void)ctxt;
4442
4443 if (argc != 2)
4444 {
4445 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4446 return 1;
4447 }
4448
4449 for (pos = args[0]; *pos; pos++)
4450 {
4451 if (*pos == '.')
4452 {
4453 end = pos;
4454 }
4455 }
4456
4457 if (end)
4458 {
4459 c = *end;
4460 *end = 0;
4461 }
4462
4463 grub_env_set(args[1], args[0]);
4464
4465 if (end)
4466 {
4467 *end = c;
4468 }
4469
4470 return 0;
4471 }
4472
4473 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4474 {
4475 int i;
4476 int len;
4477 const char *buf;
4478
4479 (void)ctxt;
4480
4481 if (argc != 2)
4482 {
4483 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4484 return 1;
4485 }
4486
4487 buf = args[0];
4488 len = (int)grub_strlen(buf);
4489 for (i = len; i > 0; i--)
4490 {
4491 if (buf[i - 1] == '/')
4492 {
4493 grub_env_set(args[1], buf + i);
4494 return 0;
4495 }
4496 }
4497
4498 grub_env_set(args[1], buf);
4499
4500 return 0;
4501 }
4502
4503 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4504 {
4505 struct grub_video_mode_info info;
4506 char buf[32];
4507
4508 (void)ctxt;
4509 (void)argc;
4510 (void)args;
4511
4512 if (!g_video_mode_list)
4513 {
4514 ventoy_enum_video_mode();
4515 }
4516
4517 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4518 {
4519 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4520 }
4521 else
4522 {
4523 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4524 }
4525
4526 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4527
4528 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4529 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4530
4531 VENTOY_CMD_RETURN(0);
4532 }
4533
4534 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4535 {
4536 struct grub_video_mode_info info;
4537 char buf[32];
4538
4539 (void)ctxt;
4540 (void)argc;
4541 (void)args;
4542
4543 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4544 {
4545 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4546 }
4547 else
4548 {
4549 grub_snprintf(buf, sizeof(buf), "0x0x0");
4550 }
4551
4552 grub_env_set(args[0], buf);
4553
4554 VENTOY_CMD_RETURN(0);
4555 }
4556
4557 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4558 {
4559 int id;
4560 char buf[32];
4561
4562 (void)ctxt;
4563 (void)argc;
4564
4565 if (!g_video_mode_list)
4566 {
4567 return 0;
4568 }
4569
4570 id = (int)grub_strtoul(args[0], NULL, 10);
4571 if (id < g_video_mode_num)
4572 {
4573 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4574 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4575 }
4576
4577 grub_env_set(args[1], buf);
4578
4579 VENTOY_CMD_RETURN(0);
4580 }
4581
4582 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4583 {
4584 grub_uint32_t i;
4585 grub_uint32_t loadsector = 0;
4586 grub_file_t file;
4587 char value[32];
4588 grub_uint32_t boot_catlog = 0;
4589 grub_uint8_t buf[512];
4590
4591 (void)ctxt;
4592
4593 if (argc != 2)
4594 {
4595 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4596 return 1;
4597 }
4598
4599 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4600 if (!file)
4601 {
4602 debug("failed to open %s\n", args[0]);
4603 return 1;
4604 }
4605
4606 boot_catlog = ventoy_get_iso_boot_catlog(file);
4607 if (boot_catlog == 0)
4608 {
4609 debug("No bootcatlog found\n");
4610 grub_file_close(file);
4611 return 1;
4612 }
4613
4614 grub_memset(buf, 0, sizeof(buf));
4615 grub_file_seek(file, boot_catlog * 2048);
4616 grub_file_read(file, buf, sizeof(buf));
4617 grub_file_close(file);
4618
4619 for (i = 0; i < sizeof(buf); i += 32)
4620 {
4621 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4622 {
4623 if (buf[i + 32] == 0x88)
4624 {
4625 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4626 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4627 break;
4628 }
4629 }
4630 }
4631
4632 if (loadsector == 0)
4633 {
4634 debug("No EFI eltorito info found\n");
4635 return 1;
4636 }
4637
4638 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4639 grub_env_set(args[1], value);
4640 VENTOY_CMD_RETURN(0);
4641 }
4642
4643 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4644 {
4645 int curpos;
4646 int printlen;
4647 grub_size_t len;
4648 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4649
4650 if (pfsdir->initrd[0])
4651 {
4652 return 1;
4653 }
4654
4655 curpos = pfsdir->curpos;
4656 len = grub_strlen(filename);
4657
4658 if (info->dir)
4659 {
4660 if ((len == 1 && filename[0] == '.') ||
4661 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4662 {
4663 return 0;
4664 }
4665
4666 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4667 pfsdir->dircnt++;
4668
4669 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4670 pfsdir->curpos = curpos + printlen;
4671 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4672 pfsdir->curpos = curpos;
4673 pfsdir->fullpath[curpos] = 0;
4674 }
4675 else
4676 {
4677 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4678 pfsdir->filecnt++;
4679
4680 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4681 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4682 {
4683 if (info->size > 32 * VTOY_SIZE_1MB)
4684 {
4685 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4686 return 1;
4687 }
4688 }
4689 }
4690
4691 return 0;
4692 }
4693
4694 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4695 {
4696 int i;
4697 char *pos = NULL;
4698 char *device_name = NULL;
4699 grub_device_t dev = NULL;
4700 grub_fs_t fs = NULL;
4701 replace_fs_dir *pfsdir = NULL;
4702
4703 (void)ctxt;
4704
4705 if (argc != 2)
4706 {
4707 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4708 return 1;
4709 }
4710
4711 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4712 if (!pfsdir)
4713 {
4714 return 1;
4715 }
4716
4717 device_name = grub_file_get_device_name(args[0]);
4718 if (!device_name)
4719 {
4720 goto fail;
4721 }
4722
4723 dev = grub_device_open(device_name);
4724 if (!dev)
4725 {
4726 goto fail;
4727 }
4728
4729 fs = grub_fs_probe(dev);
4730 if (!fs)
4731 {
4732 goto fail;
4733 }
4734
4735 pfsdir->dev = dev;
4736 pfsdir->fs = fs;
4737 pfsdir->curpos = 1;
4738 pfsdir->fullpath[0] = '/';
4739 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4740
4741 if (pfsdir->initrd[0])
4742 {
4743 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4744
4745 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4746 {
4747 if (pfsdir->initrd[i] == '/')
4748 {
4749 pfsdir->initrd[i] = '\\';
4750 }
4751 }
4752
4753 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4754 grub_env_set(args[1], pos);
4755 }
4756 else
4757 {
4758 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4759 }
4760
4761 fail:
4762
4763 grub_check_free(pfsdir);
4764 grub_check_free(device_name);
4765 check_free(dev, grub_device_close);
4766
4767 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4768 }
4769
4770 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4771 {
4772 const char *pager = NULL;
4773
4774 (void)ctxt;
4775 (void)argc;
4776 (void)args;
4777
4778 pager = grub_env_get("pager");
4779 if (NULL == pager)
4780 {
4781 g_pager_flag = 1;
4782 grub_env_set("pager", "1");
4783 }
4784 else if (pager[0] == '1')
4785 {
4786 g_pager_flag = 0;
4787 }
4788 else
4789 {
4790 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
4791 g_pager_flag = 2;
4792 grub_env_set("pager", "1");
4793 }
4794
4795 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4796 }
4797
4798 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4799 {
4800 (void)ctxt;
4801 (void)argc;
4802 (void)args;
4803
4804 if (g_pager_flag == 1)
4805 {
4806 grub_env_unset("pager");
4807 }
4808 else if (g_pager_flag == 2)
4809 {
4810 grub_env_set("pager", g_old_pager);
4811 }
4812
4813 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4814 }
4815
4816 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4817 {
4818 if (g_json_case_mis_path[0])
4819 {
4820 return 1;
4821 }
4822
4823 if (0 == info->dir && grub_strncasecmp(filename, "ventoy.json", 11) == 0)
4824 {
4825 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
4826 return 1;
4827 }
4828 return 0;
4829 }
4830
4831 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4832 {
4833 char path[16];
4834 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
4835
4836 if (g_json_case_mis_path[0])
4837 {
4838 return 1;
4839 }
4840
4841 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
4842 {
4843 if (grub_strncasecmp(filename, "ventoy", 6) == 0)
4844 {
4845 grub_snprintf(path, sizeof(path), "/%s", filename);
4846 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
4847 if (g_json_case_mis_path[0])
4848 {
4849 return 1;
4850 }
4851 }
4852 }
4853
4854 return 0;
4855 }
4856
4857 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
4858 {
4859 int fstype = 0;
4860 char *device_name = NULL;
4861 grub_device_t dev = NULL;
4862 grub_fs_t fs = NULL;
4863 chk_case_fs_dir fs_dir;
4864
4865 (void)ctxt;
4866 (void)argc;
4867 (void)args;
4868
4869 device_name = grub_file_get_device_name(args[0]);
4870 if (!device_name)
4871 {
4872 goto out;
4873 }
4874
4875 dev = grub_device_open(device_name);
4876 if (!dev)
4877 {
4878 goto out;
4879 }
4880
4881 fs = grub_fs_probe(dev);
4882 if (!fs)
4883 {
4884 goto out;
4885 }
4886
4887 fstype = ventoy_get_fs_type(fs->name);
4888 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
4889 {
4890 goto out;
4891 }
4892
4893 g_json_case_mis_path[0] = 0;
4894 fs_dir.dev = dev;
4895 fs_dir.fs = fs;
4896 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
4897
4898 if (g_json_case_mis_path[0])
4899 {
4900 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
4901 }
4902
4903 out:
4904
4905 grub_check_free(device_name);
4906 check_free(dev, grub_device_close);
4907
4908 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4909 }
4910
4911 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
4912 {
4913 grub_disk_t disk;
4914 grub_partition_t part;
4915 char priority_str[3]; /* Maximum value 15 */
4916
4917 (void)ctxt;
4918
4919 if (argc < 2 || argc > 3)
4920 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4921 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
4922
4923 /* Open the disk if it exists */
4924 disk = grub_disk_open (args[0]);
4925 if (!disk)
4926 {
4927 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4928 "Not a disk");
4929 }
4930
4931 part = grub_partition_probe (disk, args[1]);
4932 if (!part)
4933 {
4934 grub_disk_close (disk);
4935 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4936 "No such partition");
4937 }
4938
4939 if (grub_strcmp (part->partmap->name, "gpt"))
4940 {
4941 grub_disk_close (disk);
4942 return grub_error (GRUB_ERR_BAD_PART_TABLE,
4943 "Not a GPT partition");
4944 }
4945
4946 grub_snprintf (priority_str, sizeof(priority_str), "%u",
4947 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
4948
4949 if (argc == 3)
4950 {
4951 grub_env_set (args[2], priority_str);
4952 grub_env_export (args[2]);
4953 }
4954 else
4955 {
4956 grub_printf ("Priority is %s\n", priority_str);
4957 }
4958
4959 grub_disk_close (disk);
4960 return GRUB_ERR_NONE;
4961 }
4962
4963
4964
4965 /* <BEGIN>: Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4966 #if 0
4967 void ventoy_tip_set_menu_label(const char *vid)
4968 {
4969 img_info *node;
4970
4971 g_ventoy_tip_msg1 = g_ventoy_tip_msg2 = NULL;
4972 if (vid)
4973 {
4974 node = (img_info *)(void *)grub_strtoul(vid + 4, NULL, 16);
4975 if (node)
4976 {
4977 g_ventoy_tip_msg1 = node->tip1;
4978 g_ventoy_tip_msg2 = node->tip2;
4979 }
4980 }
4981 }
4982 #endif /* #if 0 */
4983 /* <END> : Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4984
4985 int ventoy_env_init(void)
4986 {
4987 char buf[64];
4988
4989 grub_env_set("vtdebug_flag", "");
4990
4991 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
4992 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4993 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
4994 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
4995
4996 ventoy_filt_register(0, ventoy_wrapper_open);
4997
4998 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
4999 if (g_grub_param)
5000 {
5001 g_grub_param->grub_env_get = grub_env_get;
5002 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5003 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5004 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5005 grub_env_set("env_param", buf);
5006 grub_env_set("ventoy_env_param", buf);
5007
5008 grub_env_export("env_param");
5009 grub_env_export("ventoy_env_param");
5010 }
5011
5012 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5013 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5014
5015 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5016 grub_env_set("vtoy_winpeshl_ini_size", buf);
5017
5018 grub_env_export("vtoy_winpeshl_ini_addr");
5019 grub_env_export("vtoy_winpeshl_ini_size");
5020
5021 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
5022 grub_env_set("vtoy_chain_file_size", buf);
5023 grub_env_export("vtoy_chain_file_size");
5024
5025 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
5026 grub_env_set("vtoy_chain_file_read", buf);
5027 grub_env_export("vtoy_chain_file_read");
5028
5029 return 0;
5030 }
5031
5032
5033
5034 static cmd_para ventoy_cmds[] =
5035 {
5036 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
5037 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
5038 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
5039 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
5040 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5041 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5042 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
5043 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
5044 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
5045 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
5046 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
5047 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
5048 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
5049 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
5050 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
5051 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
5052 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
5053 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
5054 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
5055 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
5056 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
5057 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
5058 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
5059 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
5060
5061 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
5062 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
5063 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
5064 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
5065 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
5066 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
5067 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
5068
5069 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
5070 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
5071 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
5072 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
5073 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
5074 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
5075 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
5076 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
5077 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
5078 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
5079
5080
5081 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
5082 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
5083 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
5084 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
5085 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
5086 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
5087 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
5088 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
5089 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
5090 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
5091 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
5092
5093 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
5094 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
5095 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
5096 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
5097 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
5098 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
5099 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
5100
5101 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5102 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5103 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
5104 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
5105 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
5106 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
5107 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
5108 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
5109 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
5110 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
5111
5112 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
5113 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
5114 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
5115 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
5116 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
5117 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
5118 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
5119 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
5120 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
5121
5122 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
5123 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
5124 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
5125 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
5126
5127
5128 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
5129 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
5130 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
5131
5132 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
5133 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
5134 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
5135
5136
5137 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
5138 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
5139 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
5140 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
5141 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
5142 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
5143 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
5144 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
5145 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
5146 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
5147 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
5148
5149 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
5150 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
5151 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
5152 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
5153 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
5154 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
5155 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
5156 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
5157 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
5158 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
5159
5160 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
5161 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
5162 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
5163 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
5164 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
5165 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
5166 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
5167 };
5168
5169 int ventoy_register_all_cmd(void)
5170 {
5171 grub_uint32_t i;
5172 cmd_para *cur = NULL;
5173
5174 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5175 {
5176 cur = ventoy_cmds + i;
5177 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
5178 cur->summary, cur->description, cur->parser);
5179 }
5180
5181 return 0;
5182 }
5183
5184 int ventoy_unregister_all_cmd(void)
5185 {
5186 grub_uint32_t i;
5187
5188 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5189 {
5190 grub_unregister_extcmd(ventoy_cmds[i].cmd);
5191 }
5192
5193 return 0;
5194 }
5195
5196