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