]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c
ea53303cf3cd84c0b756fa827d20f153a3c54523
[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(vtoy_tip_image_file, 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 const menu_tip *tip = NULL;
2071
2072 if (node->isocnt == 0 || node->done == 1)
2073 {
2074 return 0;
2075 }
2076
2077 if (node->parent && node->parent->dirlen < node->dirlen)
2078 {
2079 offset = node->parent->dirlen;
2080 }
2081
2082 if (node == &g_img_iterator_head)
2083 {
2084 if (g_default_menu_mode == 0)
2085 {
2086 if (g_tree_view_menu_style == 0)
2087 {
2088 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2089 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2090 " echo 'return ...' \n"
2091 "}\n", "<--");
2092 }
2093 else
2094 {
2095 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2096 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2097 " echo '%s ...' \n"
2098 "}\n", "return");
2099 }
2100 }
2101 }
2102 else
2103 {
2104 node->dir[node->dirlen - 1] = 0;
2105 dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir);
2106 if (!dir_class)
2107 {
2108 dir_class = "vtoydir";
2109 }
2110
2111 tip = ventoy_plugin_get_menu_tip(vtoy_tip_directory, node->dir);
2112
2113 dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir);
2114 if (dir_alias)
2115 {
2116 if (g_tree_view_menu_style == 0)
2117 {
2118 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2119 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2120 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2121 }
2122 else
2123 {
2124 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2125 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2126 dir_alias, dir_class, node->dir + offset, tip);
2127 }
2128 }
2129 else
2130 {
2131 dir_alias = node->dir + offset;
2132
2133 if (g_tree_view_menu_style == 0)
2134 {
2135 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2136 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2137 "DIR", dir_alias, dir_class, node->dir + offset, tip);
2138 }
2139 else
2140 {
2141 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2142 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n",
2143 dir_alias, dir_class, node->dir + offset, tip);
2144 }
2145 }
2146
2147 if (g_tree_view_menu_style == 0)
2148 {
2149 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2150 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
2151 " echo 'return ...' \n"
2152 "}\n", "<--");
2153 }
2154 else
2155 {
2156 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2157 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
2158 " echo '%s ...' \n"
2159 "}\n", "return");
2160 }
2161 }
2162
2163 while ((child = ventoy_get_min_child(node)) != NULL)
2164 {
2165 ventoy_dynamic_tree_menu(child);
2166 }
2167
2168 while ((img = ventoy_get_min_iso(node)) != NULL)
2169 {
2170 if (g_tree_view_menu_style == 0)
2171 {
2172 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2173 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2174 " %s_%s \n"
2175 "}\n",
2176 grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
2177 img->unsupport ? "[***********] " : "",
2178 img->alias ? img->alias : img->name, img->class, img,
2179 img->menu_prefix,
2180 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2181 }
2182 else
2183 {
2184 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
2185 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2186 " %s_%s \n"
2187 "}\n",
2188 img->unsupport ? "[***********] " : "",
2189 img->alias ? img->alias : img->name, img->class, img,
2190 img->menu_prefix,
2191 img->unsupport ? "unsupport_menuentry" : "common_menuentry");
2192 }
2193 }
2194
2195 if (node != &g_img_iterator_head)
2196 {
2197 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
2198 }
2199
2200 node->done = 1;
2201 return 0;
2202 }
2203
2204 static int ventoy_set_default_menu(void)
2205 {
2206 int img_len = 0;
2207 char *pos = NULL;
2208 char *end = NULL;
2209 char *def = NULL;
2210 const char *strdata = NULL;
2211 img_info *cur = NULL;
2212 img_info *default_node = NULL;
2213 const char *default_image = NULL;
2214
2215 default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE");
2216 if (default_image && default_image[0] == '/')
2217 {
2218 img_len = grub_strlen(default_image);
2219
2220 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2221 {
2222 if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0)
2223 {
2224 default_node = cur;
2225 break;
2226 }
2227 }
2228
2229 if (!default_node)
2230 {
2231 return 1;
2232 }
2233
2234 if (0 == g_default_menu_mode)
2235 {
2236 vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node);
2237 }
2238 else
2239 {
2240 def = grub_strdup(default_image);
2241 if (!def)
2242 {
2243 return 1;
2244 }
2245
2246 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\'');
2247
2248 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2249 if (strdata && strdata[0] == '/')
2250 {
2251 pos = def + grub_strlen(strdata);
2252 if (*pos == '/')
2253 {
2254 pos++;
2255 }
2256 }
2257 else
2258 {
2259 pos = def + 1;
2260 }
2261
2262 while ((end = grub_strchr(pos, '/')) != NULL)
2263 {
2264 *end = 0;
2265 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos);
2266 pos = end + 1;
2267 }
2268
2269 vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node);
2270 grub_free(def);
2271 }
2272 }
2273
2274 return 0;
2275 }
2276
2277 static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args)
2278 {
2279 img_info *next = NULL;
2280 img_info *cur = g_ventoy_img_list;
2281
2282 (void)ctxt;
2283 (void)argc;
2284 (void)args;
2285
2286 while (cur)
2287 {
2288 next = cur->next;
2289 grub_free(cur);
2290 cur = next;
2291 }
2292
2293 g_ventoy_img_list = NULL;
2294 g_ventoy_img_count = 0;
2295
2296 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2297 }
2298
2299 static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args)
2300 {
2301 long img_id = 0;
2302 img_info *cur = g_ventoy_img_list;
2303
2304 (void)ctxt;
2305
2306 if (argc != 2 || (!ventoy_is_decimal(args[0])))
2307 {
2308 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name);
2309 }
2310
2311 img_id = grub_strtol(args[0], NULL, 10);
2312 if (img_id >= g_ventoy_img_count)
2313 {
2314 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count);
2315 }
2316
2317 debug("Find image %ld name \n", img_id);
2318
2319 while (cur && img_id > 0)
2320 {
2321 img_id--;
2322 cur = cur->next;
2323 }
2324
2325 if (!cur)
2326 {
2327 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images");
2328 }
2329
2330 debug("image name is %s\n", cur->name);
2331
2332 grub_env_set(args[1], cur->name);
2333
2334 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2335 }
2336
2337 static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2338 {
2339 int len = 0;
2340 char id[32] = {0};
2341 img_info *cur = g_ventoy_img_list;
2342
2343 (void)ctxt;
2344
2345 if (argc != 1)
2346 {
2347 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2348 }
2349
2350 len = (int)grub_strlen(args[0]);
2351
2352 while (cur)
2353 {
2354 if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path))
2355 {
2356 break;
2357 }
2358 cur = cur->next;
2359 }
2360
2361 if (!cur)
2362 {
2363 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2364 }
2365
2366 grub_snprintf(id, sizeof(id), "VID_%p", cur);
2367 grub_env_set("chosen", id);
2368 grub_env_export("chosen");
2369
2370 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2371 }
2372
2373 static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
2374 {
2375 char value[32];
2376 char *pos = NULL;
2377 const char *id = NULL;
2378 img_info *cur = NULL;
2379
2380 (void)ctxt;
2381
2382 if (argc < 1 || argc > 2)
2383 {
2384 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
2385 }
2386
2387 id = grub_env_get("chosen");
2388
2389 pos = grub_strstr(id, "VID_");
2390 if (pos)
2391 {
2392 cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16);
2393 }
2394 else
2395 {
2396 cur = g_ventoy_img_list;
2397 }
2398
2399 if (!cur)
2400 {
2401 return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
2402 }
2403
2404 grub_env_set(args[0], cur->path);
2405
2406 if (argc > 1)
2407 {
2408 grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
2409 grub_env_set(args[1], value);
2410 }
2411
2412 g_svd_replace_offset = 0;
2413
2414 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2415 }
2416
2417
2418 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
2419 {
2420 int len;
2421 grub_fs_t fs;
2422 grub_device_t dev = NULL;
2423 img_info *cur = NULL;
2424 img_info *tail = NULL;
2425 img_info *min = NULL;
2426 img_info *head = NULL;
2427 const char *strdata = NULL;
2428 char *device_name = NULL;
2429 char buf[32];
2430 img_iterator_node *node = NULL;
2431 img_iterator_node *tmp = NULL;
2432
2433 (void)ctxt;
2434
2435 if (argc != 2)
2436 {
2437 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name);
2438 }
2439
2440 if (g_ventoy_img_list || g_ventoy_img_count)
2441 {
2442 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
2443 }
2444
2445 VTOY_CMD_CHECK(1);
2446
2447 g_enumerate_time_checked = 0;
2448 g_enumerate_start_time_ms = grub_get_time_ms();
2449
2450 strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2451 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2452 {
2453 g_filt_dot_underscore_file = 1;
2454 }
2455
2456 strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2457 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2458 {
2459 g_sort_case_sensitive = 1;
2460 }
2461
2462 device_name = grub_file_get_device_name(args[0]);
2463 if (!device_name)
2464 {
2465 goto fail;
2466 }
2467
2468 g_enum_dev = dev = grub_device_open(device_name);
2469 if (!dev)
2470 {
2471 goto fail;
2472 }
2473
2474 g_enum_fs = fs = grub_fs_probe(dev);
2475 if (!fs)
2476 {
2477 goto fail;
2478 }
2479
2480 if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
2481 {
2482 debug("unsupported fs:<%s>\n", fs->name);
2483 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2484 goto fail;
2485 }
2486
2487 ventoy_set_env("vtoy_iso_fs", fs->name);
2488
2489 strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2490 if (strdata && strdata[0] == '1')
2491 {
2492 g_default_menu_mode = 1;
2493 }
2494
2495 grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
2496
2497 grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
2498
2499 strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2500 if (strdata && strdata[0] == '/')
2501 {
2502 len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
2503 if (g_img_iterator_head.dir[len - 1] != '/')
2504 {
2505 g_img_iterator_head.dir[len++] = '/';
2506 }
2507 g_img_iterator_head.dirlen = len;
2508 }
2509 else
2510 {
2511 g_img_iterator_head.dirlen = 1;
2512 grub_strcpy(g_img_iterator_head.dir, "/");
2513 }
2514
2515 g_img_iterator_head.tail = &tail;
2516
2517 if (g_img_max_search_level < 0)
2518 {
2519 g_img_max_search_level = GRUB_INT_MAX;
2520 strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2521 if (strdata && ventoy_is_decimal(strdata))
2522 {
2523 g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10);
2524 }
2525 }
2526
2527 g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2528 g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2529 g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2530 g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2531 g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2532 g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2533
2534 for (node = &g_img_iterator_head; node; node = node->next)
2535 {
2536 fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node);
2537 }
2538
2539 strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2540 if (strdata && strdata[0] == '1' && strdata[1] == 0)
2541 {
2542 g_tree_view_menu_style = 1;
2543 }
2544
2545 ventoy_set_default_menu();
2546
2547 for (node = &g_img_iterator_head; node; node = node->next)
2548 {
2549 ventoy_dynamic_tree_menu(node);
2550 }
2551
2552 /* free node */
2553 node = g_img_iterator_head.next;
2554 while (node)
2555 {
2556 tmp = node->next;
2557 grub_free(node);
2558 node = tmp;
2559 }
2560
2561 /* sort image list by image name */
2562 while (g_ventoy_img_list)
2563 {
2564 min = g_ventoy_img_list;
2565 for (cur = g_ventoy_img_list->next; cur; cur = cur->next)
2566 {
2567 if (ventoy_cmp_img(min, cur) > 0)
2568 {
2569 min = cur;
2570 }
2571 }
2572
2573 if (min->prev)
2574 {
2575 min->prev->next = min->next;
2576 }
2577
2578 if (min->next)
2579 {
2580 min->next->prev = min->prev;
2581 }
2582
2583 if (min == g_ventoy_img_list)
2584 {
2585 g_ventoy_img_list = min->next;
2586 }
2587
2588 if (head == NULL)
2589 {
2590 head = tail = min;
2591 min->prev = NULL;
2592 min->next = NULL;
2593 }
2594 else
2595 {
2596 tail->next = min;
2597 min->prev = tail;
2598 min->next = NULL;
2599 tail = min;
2600 }
2601 }
2602
2603 g_ventoy_img_list = head;
2604
2605 if (g_default_menu_mode == 1)
2606 {
2607 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2608 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2609 " echo 'return ...' \n"
2610 "}\n", "<--");
2611 }
2612
2613 for (cur = g_ventoy_img_list; cur; cur = cur->next)
2614 {
2615 vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
2616 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2617 " %s_%s \n"
2618 "}\n",
2619 cur->unsupport ? "[***********] " : "",
2620 cur->alias ? cur->alias : cur->name, cur->class, cur,
2621 cur->menu_prefix,
2622 cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
2623 }
2624
2625 g_tree_script_buf[g_tree_script_pos] = 0;
2626 g_list_script_buf[g_list_script_pos] = 0;
2627
2628 grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
2629 grub_env_set(args[1], buf);
2630
2631 fail:
2632
2633 check_free(device_name, grub_free);
2634 check_free(dev, grub_device_close);
2635
2636 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2637 }
2638
2639 int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature)
2640 {
2641 grub_disk_t disk;
2642 char *device_name;
2643 char *pos;
2644 char *pos2;
2645
2646 device_name = grub_file_get_device_name(filename);
2647 if (!device_name)
2648 {
2649 return 1;
2650 }
2651
2652 pos = device_name;
2653 if (pos[0] == '(')
2654 {
2655 pos++;
2656 }
2657
2658 pos2 = grub_strstr(pos, ",");
2659 if (!pos2)
2660 {
2661 pos2 = grub_strstr(pos, ")");
2662 }
2663
2664 if (pos2)
2665 {
2666 *pos2 = 0;
2667 }
2668
2669 disk = grub_disk_open(pos);
2670 if (disk)
2671 {
2672 grub_disk_read(disk, 0, 0x180, 16, guid);
2673 grub_disk_read(disk, 0, 0x1b8, 4, signature);
2674 grub_disk_close(disk);
2675 }
2676 else
2677 {
2678 return 1;
2679 }
2680
2681 grub_free(device_name);
2682 return 0;
2683 }
2684
2685 grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file)
2686 {
2687 eltorito_descriptor desc;
2688
2689 grub_memset(&desc, 0, sizeof(desc));
2690 grub_file_seek(file, 17 * 2048);
2691 grub_file_read(file, &desc, sizeof(desc));
2692
2693 if (desc.type != 0 || desc.version != 1)
2694 {
2695 return 0;
2696 }
2697
2698 if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 ||
2699 grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0)
2700 {
2701 return 0;
2702 }
2703
2704 return desc.sector;
2705 }
2706
2707 static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector)
2708 {
2709 grub_uint8_t buf[512];
2710
2711 grub_file_seek(file, sector * 2048);
2712 grub_file_read(file, buf, sizeof(buf));
2713
2714 if (buf[0] == 0x01 && buf[1] == 0x00 &&
2715 buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88)
2716 {
2717 return *((grub_uint32_t *)(buf + 40));
2718 }
2719
2720 return 0;
2721 }
2722
2723 int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector)
2724 {
2725 int i;
2726 int x86count = 0;
2727 grub_uint8_t buf[512];
2728 grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C };
2729
2730 grub_file_seek(file, sector * 2048);
2731 grub_file_read(file, buf, sizeof(buf));
2732
2733 if (buf[0] == 0x01 && buf[1] == 0xEF)
2734 {
2735 debug("%s efi eltorito in Validation Entry\n", file->name);
2736 return 1;
2737 }
2738
2739 if (buf[0] == 0x01 && buf[1] == 0x00)
2740 {
2741 x86count++;
2742 }
2743
2744 for (i = 64; i < (int)sizeof(buf); i += 32)
2745 {
2746 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
2747 {
2748 debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2749 return 1;
2750 }
2751
2752 if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1)
2753 {
2754 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]);
2755 return 1;
2756 }
2757 }
2758
2759 if (x86count && buf[32] == 0x88 && buf[33] == 0x04)
2760 {
2761 for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++)
2762 {
2763 if (buf[36] == parttype[i])
2764 {
2765 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]);
2766 return 1;
2767 }
2768 }
2769 }
2770
2771 debug("%s does not contain efi eltorito\n", file->name);
2772 return 0;
2773 }
2774
2775 void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
2776 {
2777 char *pos;
2778 const char *fs = NULL;
2779 const char *cdprompt = NULL;
2780 grub_uint32_t i;
2781 grub_uint8_t chksum = 0;
2782 grub_disk_t disk;
2783
2784 disk = file->device->disk;
2785 grub_memcpy(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid));
2786
2787 param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
2788 param->vtoy_disk_part_id = disk->partition->number + 1;
2789 param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
2790
2791 pos = grub_strstr(file->name, "/");
2792 if (!pos)
2793 {
2794 pos = file->name;
2795 }
2796
2797 grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos);
2798
2799 ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature);
2800
2801 param->vtoy_img_size = file->size;
2802
2803 param->vtoy_reserved[0] = g_ventoy_break_level;
2804 param->vtoy_reserved[1] = g_ventoy_debug_level;
2805
2806 param->vtoy_reserved[2] = g_ventoy_chain_type;
2807
2808 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2809 param->vtoy_reserved[4] = 0;
2810 if (g_ventoy_chain_type == 1) /* Windows */
2811 {
2812 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2813 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
2814 {
2815 param->vtoy_reserved[4] = 1;
2816 }
2817 }
2818
2819 fs = ventoy_get_env("ventoy_fs_probe");
2820 if (fs && grub_strcmp(fs, "udf") == 0)
2821 {
2822 param->vtoy_reserved[3] = 1;
2823 }
2824
2825 /* calculate checksum */
2826 for (i = 0; i < sizeof(ventoy_os_param); i++)
2827 {
2828 chksum += *((grub_uint8_t *)param + i);
2829 }
2830 param->chksum = (grub_uint8_t)(0x100 - chksum);
2831
2832 return;
2833 }
2834
2835 int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2836 {
2837 grub_uint32_t i = 0;
2838 grub_uint64_t total = 0;
2839 grub_uint64_t fileblk = 0;
2840 ventoy_img_chunk *chunk = NULL;
2841
2842 for (i = 0; i < chunklist->cur_chunk; i++)
2843 {
2844 chunk = chunklist->chunk + i;
2845
2846 if (chunk->disk_start_sector <= start)
2847 {
2848 debug("%u disk start invalid %lu\n", i, (ulong)start);
2849 return 1;
2850 }
2851
2852 total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
2853 }
2854
2855 fileblk = (file->size + 511) / 512;
2856
2857 if (total != fileblk)
2858 {
2859 debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk);
2860 if ((file->size % 512) && (total + 1 == fileblk))
2861 {
2862 debug("maybe img file to be processed.\n");
2863 return 0;
2864 }
2865
2866 return 1;
2867 }
2868
2869 return 0;
2870 }
2871
2872 int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
2873 {
2874 int fs_type;
2875 int len;
2876 grub_uint32_t i = 0;
2877 grub_uint32_t sector = 0;
2878 grub_uint32_t count = 0;
2879 grub_off_t size = 0;
2880 grub_off_t read = 0;
2881
2882 fs_type = ventoy_get_fs_type(file->fs->name);
2883 if (fs_type == ventoy_fs_exfat)
2884 {
2885 grub_fat_get_file_chunk(start, file, chunklist);
2886 }
2887 else if (fs_type == ventoy_fs_ext)
2888 {
2889 grub_ext_get_file_chunk(start, file, chunklist);
2890 }
2891 else
2892 {
2893 file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
2894 file->read_hook_data = chunklist;
2895
2896 for (size = file->size; size > 0; size -= read)
2897 {
2898 read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
2899 grub_file_read(file, NULL, read);
2900 }
2901
2902 for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
2903 {
2904 chunklist->chunk[i].disk_start_sector += start;
2905 chunklist->chunk[i].disk_end_sector += start;
2906 }
2907
2908 if (ventoy_fs_udf == fs_type)
2909 {
2910 for (i = 0; i < chunklist->cur_chunk; i++)
2911 {
2912 count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
2913 chunklist->chunk[i].img_start_sector = sector;
2914 chunklist->chunk[i].img_end_sector = sector + count - 1;
2915 sector += count;
2916 }
2917 }
2918 }
2919
2920 len = (int)grub_strlen(file->name);
2921 if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) ||
2922 (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) ||
2923 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) ||
2924 (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0))
2925 {
2926 for (i = 0; i < chunklist->cur_chunk; i++)
2927 {
2928 count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector;
2929 if (count < 4)
2930 {
2931 count = 1;
2932 }
2933 else
2934 {
2935 count >>= 2;
2936 }
2937
2938 chunklist->chunk[i].img_start_sector = sector;
2939 chunklist->chunk[i].img_end_sector = sector + count - 1;
2940 sector += count;
2941 }
2942 }
2943
2944 return 0;
2945 }
2946
2947 static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
2948 {
2949 int rc;
2950 grub_file_t file;
2951 grub_disk_addr_t start;
2952
2953 (void)ctxt;
2954 (void)argc;
2955
2956 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2957 if (!file)
2958 {
2959 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
2960 }
2961
2962 g_conf_replace_node = NULL;
2963 g_conf_replace_offset = 0;
2964
2965 if (g_img_chunk_list.chunk)
2966 {
2967 grub_free(g_img_chunk_list.chunk);
2968 }
2969
2970 if (ventoy_get_fs_type(file->fs->name) >= ventoy_fs_max)
2971 {
2972 grub_file_close(file);
2973 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name);
2974 }
2975
2976 /* get image chunk data */
2977 grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list));
2978 g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2979 if (NULL == g_img_chunk_list.chunk)
2980 {
2981 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2982 }
2983
2984 g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
2985 g_img_chunk_list.cur_chunk = 0;
2986
2987 start = file->device->disk->partition->start;
2988
2989 ventoy_get_block_list(file, &g_img_chunk_list, start);
2990
2991 rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
2992 grub_file_close(file);
2993
2994 if (rc)
2995 {
2996 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
2997 }
2998
2999 grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
3000 grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace));
3001 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3002 }
3003
3004 static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args)
3005 {
3006 grub_uint64_t offset = 0;
3007 grub_uint32_t align = 0;
3008 grub_file_t file = NULL;
3009 conf_replace *node = NULL;
3010
3011 (void)ctxt;
3012 (void)argc;
3013 (void)args;
3014
3015 debug("select conf replace argc:%d\n", argc);
3016
3017 if (argc < 2)
3018 {
3019 return 0;
3020 }
3021
3022 node = ventoy_plugin_find_conf_replace(args[1]);
3023 if (!node)
3024 {
3025 debug("Conf replace not found for %s\n", args[1]);
3026 goto end;
3027 }
3028
3029 debug("Find conf replace for %s\n", args[1]);
3030
3031 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf);
3032 if (file)
3033 {
3034 offset = grub_iso9660_get_last_file_dirent_pos(file);
3035 grub_file_close(file);
3036 }
3037 else if (node->img > 0)
3038 {
3039 offset = 0;
3040 }
3041 else
3042 {
3043 debug("<(loop)%s> NOT exist\n", node->orgconf);
3044 goto end;
3045 }
3046
3047 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf);
3048 if (!file)
3049 {
3050 debug("New config file <%s%s> NOT exist\n", args[0], node->newconf);
3051 goto end;
3052 }
3053
3054 align = ((int)file->size + 2047) / 2048 * 2048;
3055
3056 if (align > vtoy_max_replace_file_size)
3057 {
3058 debug("New config file <%s%s> too big\n", args[0], node->newconf);
3059 goto end;
3060 }
3061
3062 grub_file_read(file, g_conf_replace_new_buf, file->size);
3063 g_conf_replace_new_len = (int)file->size;
3064 g_conf_replace_new_len_align = align;
3065
3066 g_conf_replace_node = node;
3067 g_conf_replace_offset = offset + 2;
3068
3069 if (node->img > 0)
3070 {
3071 g_grub_param->img_replace.magic = GRUB_IMG_REPLACE_MAGIC;
3072 g_grub_param->img_replace.old_name_cnt = 1;
3073 grub_snprintf(g_grub_param->img_replace.old_file_name[0], 256, "%s", node->orgconf);
3074 }
3075
3076 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len);
3077
3078 end:
3079 if (file)
3080 {
3081 grub_file_close(file);
3082 }
3083 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3084 }
3085
3086 static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3087 {
3088 int i = 0;
3089 int pos = 0;
3090 int defidx = 1;
3091 char *buf = NULL;
3092 char configfile[128];
3093 install_template *node = NULL;
3094
3095 (void)ctxt;
3096 (void)argc;
3097 (void)args;
3098
3099 debug("select auto installation argc:%d\n", argc);
3100
3101 if (argc < 1)
3102 {
3103 return 0;
3104 }
3105
3106 node = ventoy_plugin_find_install_template(args[0]);
3107 if (!node)
3108 {
3109 debug("Auto install template not found for %s\n", args[0]);
3110 return 0;
3111 }
3112
3113 if (node->autosel >= 0 && node->autosel <= node->templatenum)
3114 {
3115 defidx = node->autosel;
3116 if (node->timeout < 0)
3117 {
3118 node->cursel = node->autosel - 1;
3119 debug("Auto install template auto select %d\n", node->autosel);
3120 return 0;
3121 }
3122 }
3123
3124 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3125 if (!buf)
3126 {
3127 return 0;
3128 }
3129
3130 if (node->timeout > 0)
3131 {
3132 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3133 }
3134
3135 vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
3136 " echo %s\n}\n", "");
3137
3138 for (i = 0; i < node->templatenum; i++)
3139 {
3140 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\"{\n"
3141 " echo \"\"\n}\n",
3142 node->templatepath[i].path);
3143 }
3144
3145 g_ventoy_menu_esc = 1;
3146 g_ventoy_suppress_esc = 1;
3147 g_ventoy_suppress_esc_default = defidx;
3148
3149 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3150 grub_script_execute_sourcecode(configfile);
3151
3152 g_ventoy_menu_esc = 0;
3153 g_ventoy_suppress_esc = 0;
3154 g_ventoy_suppress_esc_default = 1;
3155
3156 grub_free(buf);
3157
3158 node->cursel = g_ventoy_last_entry - 1;
3159
3160 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3161 }
3162
3163 static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3164 {
3165 int i = 0;
3166 int pos = 0;
3167 int defidx = 1;
3168 char *buf = NULL;
3169 char configfile[128];
3170 persistence_config *node;
3171
3172 (void)ctxt;
3173 (void)argc;
3174 (void)args;
3175
3176 debug("select persistence argc:%d\n", argc);
3177
3178 if (argc < 1)
3179 {
3180 return 0;
3181 }
3182
3183 node = ventoy_plugin_find_persistent(args[0]);
3184 if (!node)
3185 {
3186 debug("Persistence image not found for %s\n", args[0]);
3187 return 0;
3188 }
3189
3190 if (node->autosel >= 0 && node->autosel <= node->backendnum)
3191 {
3192 defidx = node->autosel;
3193 if (node->timeout < 0)
3194 {
3195 node->cursel = node->autosel - 1;
3196 debug("Persistence image auto select %d\n", node->autosel);
3197 return 0;
3198 }
3199 }
3200
3201 buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
3202 if (!buf)
3203 {
3204 return 0;
3205 }
3206
3207 if (node->timeout > 0)
3208 {
3209 vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout);
3210 }
3211
3212 vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
3213 " echo %s\n}\n", "");
3214
3215 for (i = 0; i < node->backendnum; i++)
3216 {
3217 vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
3218 " echo \"\"\n}\n",
3219 node->backendpath[i].path);
3220
3221 }
3222
3223 g_ventoy_menu_esc = 1;
3224 g_ventoy_suppress_esc = 1;
3225 g_ventoy_suppress_esc_default = defidx;
3226
3227 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
3228 grub_script_execute_sourcecode(configfile);
3229
3230 g_ventoy_menu_esc = 0;
3231 g_ventoy_suppress_esc = 0;
3232 g_ventoy_suppress_esc_default = 1;
3233
3234 grub_free(buf);
3235
3236 node->cursel = g_ventoy_last_entry - 1;
3237
3238 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3239 }
3240
3241 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
3242 {
3243 grub_uint32_t i;
3244 ventoy_img_chunk *cur;
3245
3246 (void)ctxt;
3247 (void)argc;
3248 (void)args;
3249
3250 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
3251 {
3252 cur = g_img_chunk_list.chunk + i;
3253 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3254 cur->img_start_sector, cur->img_end_sector,
3255 (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector
3256 );
3257 }
3258
3259 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3260 }
3261
3262 static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
3263 {
3264 grub_uint32_t i;
3265 grub_file_t file;
3266 ventoy_img_chunk_list chunklist;
3267
3268 (void)ctxt;
3269 (void)argc;
3270
3271 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3272 if (!file)
3273 {
3274 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
3275 }
3276
3277 /* get image chunk data */
3278 grub_memset(&chunklist, 0, sizeof(chunklist));
3279 chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
3280 if (NULL == chunklist.chunk)
3281 {
3282 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
3283 }
3284
3285 chunklist.max_chunk = DEFAULT_CHUNK_NUM;
3286 chunklist.cur_chunk = 0;
3287
3288 ventoy_get_block_list(file, &chunklist, 0);
3289
3290 if (0 != ventoy_check_block_list(file, &chunklist, 0))
3291 {
3292 grub_printf("########## UNSUPPORTED ###############\n");
3293 }
3294
3295 grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
3296
3297 for (i = 0; i < chunklist.cur_chunk; i++)
3298 {
3299 grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
3300 (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
3301 }
3302
3303 grub_printf("\n==================================\n");
3304
3305 for (i = 0; i < chunklist.cur_chunk; i++)
3306 {
3307 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
3308 (ulonglong)chunklist.chunk[i].img_start_sector,
3309 (ulonglong)chunklist.chunk[i].img_end_sector,
3310 (ulonglong)chunklist.chunk[i].disk_start_sector,
3311 (ulonglong)chunklist.chunk[i].disk_end_sector
3312 );
3313 }
3314
3315 grub_free(chunklist.chunk);
3316 grub_file_close(file);
3317
3318 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3319 }
3320
3321 static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
3322 {
3323 int i;
3324 ventoy_grub_param_file_replace *replace = NULL;
3325
3326 (void)ctxt;
3327 (void)argc;
3328 (void)args;
3329
3330 if (argc >= 2)
3331 {
3332 replace = &(g_grub_param->file_replace);
3333 replace->magic = GRUB_FILE_REPLACE_MAGIC;
3334
3335 replace->old_name_cnt = 0;
3336 for (i = 0; i < 4 && i + 1 < argc; i++)
3337 {
3338 replace->old_name_cnt++;
3339 grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
3340 }
3341
3342 replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
3343 }
3344
3345 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3346 }
3347
3348 static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args)
3349 {
3350 char buf[32];
3351 ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace);
3352
3353 (void)ctxt;
3354
3355 if (argc >= 1)
3356 {
3357 grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt);
3358 grub_env_set(args[0], buf);
3359 }
3360
3361 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
3362 }
3363
3364 static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3365 {
3366 (void)ctxt;
3367 (void)argc;
3368 (void)args;
3369
3370 if (argc == 0)
3371 {
3372 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
3373 grub_printf("%s", g_list_script_buf);
3374 }
3375 else
3376 {
3377 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
3378 grub_printf("%s", g_tree_script_buf);
3379 }
3380
3381 return 0;
3382 }
3383
3384 static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args)
3385 {
3386 img_info *cur = g_ventoy_img_list;
3387
3388 (void)ctxt;
3389 (void)argc;
3390 (void)args;
3391
3392 while (cur)
3393 {
3394 grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index);
3395 grub_printf("name:<%s>\n\n", cur->name);
3396 cur = cur->next;
3397 }
3398
3399 return 0;
3400 }
3401
3402 static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args)
3403 {
3404 (void)ctxt;
3405 (void)argc;
3406 (void)args;
3407
3408 ventoy_plugin_dump_injection();
3409
3410 return 0;
3411 }
3412
3413 static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
3414 {
3415 (void)ctxt;
3416 (void)argc;
3417 (void)args;
3418
3419 ventoy_plugin_dump_auto_install();
3420
3421 return 0;
3422 }
3423
3424 static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
3425 {
3426 (void)ctxt;
3427 (void)argc;
3428 (void)args;
3429
3430 ventoy_plugin_dump_persistence();
3431
3432 return 0;
3433 }
3434
3435 static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
3436 {
3437 (void)ctxt;
3438 (void)argc;
3439 (void)args;
3440
3441 if (argc != 1)
3442 {
3443 return 1;
3444 }
3445
3446 if (args[0][0] == '0')
3447 {
3448 return g_ventoy_memdisk_mode ? 0 : 1;
3449 }
3450 else if (args[0][0] == '1')
3451 {
3452 return g_ventoy_iso_raw ? 0 : 1;
3453 }
3454 else if (args[0][0] == '2')
3455 {
3456 return g_ventoy_iso_uefi_drv ? 0 : 1;
3457 }
3458 else if (args[0][0] == '3')
3459 {
3460 return g_ventoy_grub2_mode ? 0 : 1;
3461 }
3462 else if (args[0][0] == '4')
3463 {
3464 return g_ventoy_wimboot_mode ? 0 : 1;
3465 }
3466
3467 return 1;
3468 }
3469
3470 static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
3471 {
3472 static int configfile_mode = 0;
3473 char memfile[128] = {0};
3474
3475 (void)ctxt;
3476 (void)argc;
3477 (void)args;
3478
3479 /*
3480 * args[0]: 0:normal 1:configfile
3481 * args[1]: 0:list_buf 1:tree_buf
3482 */
3483
3484 if (argc != 2)
3485 {
3486 debug("Invalid argc %d\n", argc);
3487 return 0;
3488 }
3489
3490 VTOY_CMD_CHECK(1);
3491
3492 if (args[0][0] == '0')
3493 {
3494 if (args[1][0] == '0')
3495 {
3496 grub_script_execute_sourcecode(g_list_script_buf);
3497 }
3498 else
3499 {
3500 grub_script_execute_sourcecode(g_tree_script_buf);
3501 }
3502 }
3503 else
3504 {
3505 if (configfile_mode)
3506 {
3507 debug("Now already in F3 mode %d\n", configfile_mode);
3508 return 0;
3509 }
3510
3511 if (args[1][0] == '0')
3512 {
3513 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3514 (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
3515 }
3516 else
3517 {
3518 g_ventoy_last_entry = -1;
3519 grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
3520 (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
3521 }
3522
3523 configfile_mode = 1;
3524 grub_script_execute_sourcecode(memfile);
3525 configfile_mode = 0;
3526 }
3527
3528 return 0;
3529 }
3530
3531 static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args)
3532 {
3533 grub_file_t file;
3534
3535 (void)ctxt;
3536
3537 if (argc != 1)
3538 {
3539 return 1;
3540 }
3541
3542 g_ventoy_case_insensitive = 1;
3543 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
3544 g_ventoy_case_insensitive = 0;
3545
3546 grub_errno = 0;
3547
3548 if (file)
3549 {
3550 grub_file_close(file);
3551 return 0;
3552 }
3553 return 1;
3554 }
3555
3556 static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
3557 {
3558 int id = 0;
3559 int find = 0;
3560 grub_disk_t disk;
3561 const char *isopath = NULL;
3562 char hdname[32];
3563 ventoy_mbr_head mbr;
3564
3565 (void)ctxt;
3566 (void)argc;
3567
3568 if (argc != 1)
3569 {
3570 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
3571 }
3572
3573 isopath = grub_env_get("vtoy_iso_part");
3574 if (!isopath)
3575 {
3576 debug("isopath is null %p\n", isopath);
3577 return 0;
3578 }
3579
3580 debug("isopath is %s\n", isopath);
3581
3582 for (id = 0; id < 30 && (find == 0); id++)
3583 {
3584 grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
3585 if (grub_strstr(isopath, hdname))
3586 {
3587 debug("skip %s ...\n", hdname);
3588 continue;
3589 }
3590
3591 grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
3592
3593 disk = grub_disk_open(hdname);
3594 if (!disk)
3595 {
3596 debug("%s not exist\n", hdname);
3597 break;
3598 }
3599
3600 grub_memset(&mbr, 0, sizeof(mbr));
3601 if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
3602 {
3603 if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
3604 {
3605 if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
3606 mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
3607 {
3608
3609 grub_env_set(args[0], hdname);
3610 find = 1;
3611 }
3612 }
3613 debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
3614 }
3615 else
3616 {
3617 debug("read %s failed\n", hdname);
3618 }
3619
3620 grub_disk_close(disk);
3621 }
3622
3623 return 0;
3624 }
3625
3626 static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args)
3627 {
3628 int len = 1024;
3629 grub_file_t file;
3630 char *buf = NULL;
3631
3632 (void)ctxt;
3633 (void)argc;
3634
3635 if (argc != 2)
3636 {
3637 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name);
3638 }
3639
3640 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3641 if (!file)
3642 {
3643 debug("failed to open file %s\n", args[0]);
3644 return 0;
3645 }
3646
3647 buf = grub_malloc(len);
3648 if (!buf)
3649 {
3650 goto end;
3651 }
3652
3653 buf[len - 1] = 0;
3654 grub_file_read(file, buf, len - 1);
3655
3656 ventoy_get_line(buf);
3657 ventoy_set_env(args[1], buf);
3658
3659 end:
3660
3661 grub_check_free(buf);
3662 grub_file_close(file);
3663
3664 return 0;
3665 }
3666
3667 static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data)
3668 {
3669 int *pCnt = (int *)data;
3670
3671 (void)disk;
3672
3673 (*pCnt)++;
3674 g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos,
3675 "0 %llu linear /dev/ventoy %llu\n",
3676 (ulonglong)partition->len, (ulonglong)partition->start);
3677
3678 return 0;
3679 }
3680
3681 static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args)
3682 {
3683 int cnt = 0;
3684 char *device_name = NULL;
3685 grub_device_t dev = NULL;
3686 char buf[64];
3687
3688 (void)ctxt;
3689
3690 g_part_list_pos = 0;
3691 grub_env_unset("vtoy_img_part_file");
3692
3693 if (argc != 1)
3694 {
3695 return 1;
3696 }
3697
3698 device_name = grub_file_get_device_name(args[0]);
3699 if (!device_name)
3700 {
3701 debug("ventoy_cmd_img_part_info failed, %s\n", args[0]);
3702 goto end;
3703 }
3704
3705 dev = grub_device_open(device_name);
3706 if (!dev)
3707 {
3708 debug("grub_device_open failed, %s\n", device_name);
3709 goto end;
3710 }
3711
3712 grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt);
3713
3714 grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos);
3715 grub_env_set("vtoy_img_part_file", buf);
3716
3717 grub_snprintf(buf, sizeof(buf), "%d", cnt);
3718 grub_env_set("vtoy_img_part_cnt", buf);
3719
3720 end:
3721
3722 check_free(device_name, grub_free);
3723 check_free(dev, grub_device_close);
3724
3725 return 0;
3726 }
3727
3728
3729 static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args)
3730 {
3731 int rc = 1;
3732 grub_file_t file;
3733 char *buf = NULL;
3734
3735 (void)ctxt;
3736 (void)argc;
3737
3738 if (argc != 2)
3739 {
3740 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name);
3741 }
3742
3743 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3744 if (!file)
3745 {
3746 debug("failed to open file %s\n", args[0]);
3747 return 1;
3748 }
3749
3750 buf = grub_malloc(file->size + 1);
3751 if (!buf)
3752 {
3753 goto end;
3754 }
3755
3756 buf[file->size] = 0;
3757 grub_file_read(file, buf, file->size);
3758
3759 if (grub_strstr(buf, args[1]))
3760 {
3761 rc = 0;
3762 }
3763
3764 end:
3765
3766 grub_check_free(buf);
3767 grub_file_close(file);
3768
3769 return rc;
3770 }
3771
3772 static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args)
3773 {
3774 int len;
3775 grub_file_t file;
3776 char buf[64];
3777 grub_uint64_t size;
3778 ventoy_iso9660_vd pvd;
3779
3780 (void)ctxt;
3781 (void)argc;
3782
3783 if (argc != 4)
3784 {
3785 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name);
3786 }
3787
3788 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3789 if (!file)
3790 {
3791 debug("failed to open file %s\n", args[0]);
3792 return 0;
3793 }
3794
3795 grub_file_seek(file, 16 * 2048);
3796 len = (int)grub_file_read(file, &pvd, sizeof(pvd));
3797 if (len != sizeof(pvd))
3798 {
3799 debug("failed to read pvd %d\n", len);
3800 goto end;
3801 }
3802
3803 grub_memset(buf, 0, sizeof(buf));
3804 grub_memcpy(buf, pvd.sys, sizeof(pvd.sys));
3805 ventoy_set_env(args[1], buf);
3806
3807 grub_memset(buf, 0, sizeof(buf));
3808 grub_memcpy(buf, pvd.vol, sizeof(pvd.vol));
3809 ventoy_set_env(args[2], buf);
3810
3811 size = pvd.space;
3812 size *= 2048;
3813 grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size);
3814 ventoy_set_env(args[3], buf);
3815
3816 end:
3817 grub_file_close(file);
3818
3819 return 0;
3820 }
3821
3822 static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args)
3823 {
3824 int len;
3825 grub_file_t file;
3826 char buf[64];
3827
3828 (void)ctxt;
3829 (void)argc;
3830
3831 if (argc != 2)
3832 {
3833 return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name);
3834 }
3835
3836 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3837 if (!file)
3838 {
3839 debug("failed to open file %s\n", args[0]);
3840 return 0;
3841 }
3842
3843 grub_memset(buf, 0, sizeof(buf));
3844 grub_file_seek(file, 16 * 2048 + 813);
3845 len = (int)grub_file_read(file, buf, 17);
3846 if (len != 17)
3847 {
3848 debug("failed to read create date %d\n", len);
3849 goto end;
3850 }
3851
3852 ventoy_set_env(args[1], buf);
3853
3854 end:
3855 grub_file_close(file);
3856
3857 return 0;
3858 }
3859
3860 static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3861 {
3862 (void)ctxt;
3863 (void)argc;
3864 (void)args;
3865
3866 ventoy_env_hook_root(1);
3867
3868 return 0;
3869 }
3870
3871 static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
3872 {
3873 (void)ctxt;
3874 (void)argc;
3875 (void)args;
3876
3877 ventoy_env_hook_root(0);
3878
3879 return 0;
3880 }
3881
3882 #ifdef GRUB_MACHINE_EFI
3883 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3884 {
3885 int ret = 1;
3886 grub_uint8_t *var;
3887 grub_size_t size;
3888 grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
3889
3890 (void)ctxt;
3891 (void)argc;
3892 (void)args;
3893
3894 var = grub_efi_get_variable("SecureBoot", &global, &size);
3895 if (var && *var == 1)
3896 {
3897 return 0;
3898 }
3899
3900 return ret;
3901 }
3902 #else
3903 static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args)
3904 {
3905 (void)ctxt;
3906 (void)argc;
3907 (void)args;
3908 return 1;
3909 }
3910 #endif
3911
3912 static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args)
3913 {
3914 int i;
3915 int ret = 1;
3916 grub_file_t file;
3917 grub_uint64_t FileSectors = 0;
3918 ventoy_gpt_info *gpt = NULL;
3919 ventoy_part_table *pt = NULL;
3920 grub_uint8_t zeroguid[16] = {0};
3921
3922 (void)ctxt;
3923 (void)argc;
3924
3925 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
3926 if (!file)
3927 {
3928 debug("failed to open file %s\n", args[0]);
3929 return 1;
3930 }
3931
3932 if (file->size % 512)
3933 {
3934 debug("unaligned file size: %llu\n", (ulonglong)file->size);
3935 goto out;
3936 }
3937
3938 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
3939 if (!gpt)
3940 {
3941 goto out;
3942 }
3943
3944 FileSectors = file->size / 512;
3945
3946 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
3947 if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
3948 {
3949 debug("This is EFI partition table\n");
3950
3951 for (i = 0; i < 128; i++)
3952 {
3953 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
3954 {
3955 if (FileSectors < gpt->PartTbl[i].LastLBA)
3956 {
3957 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3958 (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors);
3959 goto out;
3960 }
3961 }
3962 }
3963 }
3964 else
3965 {
3966 debug("This is MBR partition table\n");
3967
3968 for (i = 0; i < 4; i++)
3969 {
3970 pt = gpt->MBR.PartTbl + i;
3971 if (FileSectors < pt->StartSectorId + pt->SectorCount)
3972 {
3973 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i,
3974 (ulonglong)(pt->StartSectorId + pt->SectorCount),
3975 (ulonglong)FileSectors);
3976 goto out;
3977 }
3978 }
3979 }
3980
3981 ret = 0;
3982
3983 out:
3984 grub_file_close(file);
3985 grub_check_free(gpt);
3986 grub_errno = GRUB_ERR_NONE;
3987 return ret;
3988 }
3989
3990 static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args)
3991 {
3992 int i;
3993 int ret;
3994
3995 (void)ctxt;
3996 (void)argc;
3997 (void)args;
3998
3999 for (i = 0; i < 500; i++)
4000 {
4001 ret = grub_getkey_noblock();
4002 if (ret == GRUB_TERM_NO_KEY)
4003 {
4004 break;
4005 }
4006 }
4007
4008 if (i >= 500)
4009 {
4010 grub_cls();
4011 grub_printf("\n\n Still have key input after clear.\n");
4012 grub_refresh();
4013 grub_sleep(5);
4014 }
4015
4016 return 0;
4017 }
4018
4019 static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args)
4020 {
4021 int i;
4022 int buflen;
4023 int datalen;
4024 int loclen;
4025 int img_chunk_num;
4026 int image_sector_size;
4027 char cmd[64];
4028 ventoy_chain_head *chain;
4029 ventoy_img_chunk *chunk;
4030 ventoy_os_param *osparam;
4031 ventoy_image_location *location;
4032 ventoy_image_disk_region *region;
4033 struct grub_acpi_table_header *acpi;
4034
4035 (void)ctxt;
4036
4037 if (argc != 2)
4038 {
4039 return 1;
4040 }
4041
4042 debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]);
4043
4044 chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16);
4045 if (!chain)
4046 {
4047 return 1;
4048 }
4049
4050 image_sector_size = (int)grub_strtol(args[1], NULL, 10);
4051
4052 if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16))
4053 {
4054 debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1);
4055 return 1;
4056 }
4057
4058 img_chunk_num = chain->img_chunk_num;
4059
4060 loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
4061 datalen = sizeof(ventoy_os_param) + loclen;
4062
4063 buflen = sizeof(struct grub_acpi_table_header) + datalen;
4064 acpi = grub_zalloc(buflen);
4065 if (!acpi)
4066 {
4067 return 1;
4068 }
4069
4070 /* Step1: Fill acpi table header */
4071 grub_memcpy(acpi->signature, "VTOY", 4);
4072 acpi->length = buflen;
4073 acpi->revision = 1;
4074 grub_memcpy(acpi->oemid, "VENTOY", 6);
4075 grub_memcpy(acpi->oemtable, "OSPARAMS", 8);
4076 acpi->oemrev = 1;
4077 acpi->creator_id[0] = 1;
4078 acpi->creator_rev = 1;
4079
4080 /* Step2: Fill data */
4081 osparam = (ventoy_os_param *)(acpi + 1);
4082 grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param));
4083 osparam->vtoy_img_location_addr = 0;
4084 osparam->vtoy_img_location_len = loclen;
4085 osparam->chksum = 0;
4086 osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param));
4087
4088 location = (ventoy_image_location *)(osparam + 1);
4089 grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid));
4090 location->image_sector_size = image_sector_size;
4091 location->disk_sector_size = chain->disk_sector_size;
4092 location->region_count = img_chunk_num;
4093
4094 region = location->regions;
4095 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
4096 if (512 == image_sector_size)
4097 {
4098 for (i = 0; i < img_chunk_num; i++)
4099 {
4100 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
4101 region->image_start_sector = chunk->img_start_sector * 4;
4102 region->disk_start_sector = chunk->disk_start_sector;
4103 region++;
4104 chunk++;
4105 }
4106 }
4107 else
4108 {
4109 for (i = 0; i < img_chunk_num; i++)
4110 {
4111 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
4112 region->image_start_sector = chunk->img_start_sector;
4113 region->disk_start_sector = chunk->disk_start_sector;
4114 region++;
4115 chunk++;
4116 }
4117 }
4118
4119 /* Step3: Fill acpi checksum */
4120 acpi->checksum = 0;
4121 acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length);
4122
4123 /* load acpi table */
4124 grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length);
4125 grub_script_execute_sourcecode(cmd);
4126
4127 grub_free(acpi);
4128
4129 VENTOY_CMD_RETURN(0);
4130 }
4131
4132 static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4133 {
4134 (void)ctxt;
4135 (void)argc;
4136 (void)args;
4137
4138 g_ventoy_last_entry_back = g_ventoy_last_entry;
4139 g_ventoy_last_entry = -1;
4140
4141 return 0;
4142 }
4143
4144 static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args)
4145 {
4146 (void)ctxt;
4147 (void)argc;
4148 (void)args;
4149
4150 g_ventoy_last_entry = g_ventoy_last_entry_back;
4151
4152 return 0;
4153 }
4154
4155 static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data)
4156 {
4157 const char *pos = filename + 1;
4158
4159 if (info->dir)
4160 {
4161 while (*pos)
4162 {
4163 if (*pos == '.')
4164 {
4165 if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9'))
4166 {
4167 grub_strncpy((char *)data, filename, 128);
4168 return 1;
4169 }
4170 }
4171 pos++;
4172 }
4173 }
4174
4175 return 0;
4176 }
4177
4178 static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args)
4179 {
4180 int rc = 1;
4181 char *device_name = NULL;
4182 grub_device_t dev = NULL;
4183 grub_fs_t fs = NULL;
4184 char buf[128] = {0};
4185
4186 (void)ctxt;
4187
4188 if (argc != 3)
4189 {
4190 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc);
4191 return 1;
4192 }
4193
4194 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]);
4195
4196 device_name = grub_file_get_device_name(args[0]);
4197 if (!device_name)
4198 {
4199 debug("grub_file_get_device_name failed, %s\n", args[0]);
4200 goto end;
4201 }
4202
4203 dev = grub_device_open(device_name);
4204 if (!dev)
4205 {
4206 debug("grub_device_open failed, %s\n", device_name);
4207 goto end;
4208 }
4209
4210 fs = grub_fs_probe(dev);
4211 if (!fs)
4212 {
4213 debug("grub_fs_probe failed, %s\n", device_name);
4214 goto end;
4215 }
4216
4217 fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf);
4218
4219 if (buf[0])
4220 {
4221 ventoy_set_env(args[2], buf);
4222 }
4223
4224 rc = 0;
4225
4226 end:
4227
4228 check_free(device_name, grub_free);
4229 check_free(dev, grub_device_close);
4230
4231 return rc;
4232 }
4233
4234 int ventoy_load_part_table(const char *diskname)
4235 {
4236 char name[64];
4237 int ret;
4238 grub_disk_t disk;
4239 grub_device_t dev;
4240
4241 g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info));
4242 if (!g_ventoy_part_info)
4243 {
4244 return 1;
4245 }
4246
4247 disk = grub_disk_open(diskname);
4248 if (!disk)
4249 {
4250 debug("Failed to open disk %s\n", diskname);
4251 return 1;
4252 }
4253
4254 g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size);
4255
4256 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info);
4257 grub_disk_close(disk);
4258
4259 grub_snprintf(name, sizeof(name), "%s,1", diskname);
4260 dev = grub_device_open(name);
4261 if (dev)
4262 {
4263 /* Check for official Ventoy device */
4264 ret = ventoy_check_official_device(dev);
4265 grub_device_close(dev);
4266
4267 if (ret)
4268 {
4269 return 1;
4270 }
4271 }
4272
4273 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4274 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4275
4276 return 0;
4277 }
4278
4279 static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args)
4280 {
4281 int ret;
4282
4283 (void)argc;
4284 (void)ctxt;
4285
4286 ret = ventoy_load_part_table(args[0]);
4287 if (ret)
4288 {
4289 grub_exit();
4290 }
4291
4292 g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0);
4293 g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1);
4294
4295 return 0;
4296 }
4297
4298 static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args)
4299 {
4300 int ret = 1;
4301 const char *vcfg = NULL;
4302
4303 (void)argc;
4304 (void)ctxt;
4305
4306 vcfg = ventoy_plugin_get_custom_boot(args[0]);
4307 if (vcfg)
4308 {
4309 debug("custom boot <%s>:<%s>\n", args[0], vcfg);
4310 grub_env_set(args[1], vcfg);
4311 ret = 0;
4312 }
4313 else
4314 {
4315 debug("custom boot <%s>:<NOT FOUND>\n", args[0]);
4316 }
4317
4318 grub_errno = 0;
4319 return ret;
4320 }
4321
4322
4323 static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args)
4324 {
4325 int id;
4326 grub_uint8_t zeroguid[16] = {0};
4327
4328 (void)argc;
4329 (void)ctxt;
4330
4331 id = (int)grub_strtoul(args[0], NULL, 10);
4332 grub_errno = 0;
4333
4334 if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0)
4335 {
4336 if (id >= 1 && id <= 128)
4337 {
4338 if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16))
4339 {
4340 return 0;
4341 }
4342 }
4343 }
4344 else
4345 {
4346 if (id >= 1 && id <= 4)
4347 {
4348 if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag)
4349 {
4350 return 0;
4351 }
4352 }
4353 }
4354
4355 return 1;
4356 }
4357
4358 static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args)
4359 {
4360 int rc = 1;
4361 char *device_name = NULL;
4362 grub_device_t dev = NULL;
4363 grub_fs_t fs = NULL;
4364 char *label = NULL;
4365
4366 (void)ctxt;
4367
4368 debug("get fs label for %s\n", args[0]);
4369
4370 if (argc != 2)
4371 {
4372 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc);
4373 return 1;
4374 }
4375
4376 device_name = grub_file_get_device_name(args[0]);
4377 if (!device_name)
4378 {
4379 debug("grub_file_get_device_name failed, %s\n", args[0]);
4380 goto end;
4381 }
4382
4383 dev = grub_device_open(device_name);
4384 if (!dev)
4385 {
4386 debug("grub_device_open failed, %s\n", device_name);
4387 goto end;
4388 }
4389
4390 fs = grub_fs_probe(dev);
4391 if (NULL == fs || NULL == fs->fs_label)
4392 {
4393 debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label);
4394 goto end;
4395 }
4396
4397 fs->fs_label(dev, &label);
4398 if (label)
4399 {
4400 debug("label=<%s>\n", label);
4401 ventoy_set_env(args[1], label);
4402 grub_free(label);
4403 }
4404
4405 rc = 0;
4406
4407 end:
4408
4409 check_free(device_name, grub_free);
4410 check_free(dev, grub_device_close);
4411
4412 return rc;
4413 }
4414
4415 static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4416 {
4417 if (!info->dir)
4418 {
4419 grub_snprintf((char *)data, 256, "%s", filename);
4420 return 1;
4421 }
4422
4423 return 0;
4424 }
4425
4426 static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4427 {
4428 if (info->dir && filename && filename[0] != '.')
4429 {
4430 grub_snprintf((char *)data, 256, "%s", filename);
4431 return 1;
4432 }
4433
4434 return 0;
4435 }
4436
4437 static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook)
4438 {
4439 int rc = 1;
4440 char *device_name = NULL;
4441 grub_device_t dev = NULL;
4442 grub_fs_t fs = NULL;
4443 char name[256] ={0};
4444
4445 if (argc != 3)
4446 {
4447 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc);
4448 return 1;
4449 }
4450
4451 device_name = grub_file_get_device_name(args[0]);
4452 if (!device_name)
4453 {
4454 debug("grub_file_get_device_name failed, %s\n", args[0]);
4455 goto end;
4456 }
4457
4458 dev = grub_device_open(device_name);
4459 if (!dev)
4460 {
4461 debug("grub_device_open failed, %s\n", device_name);
4462 goto end;
4463 }
4464
4465 fs = grub_fs_probe(dev);
4466 if (!fs)
4467 {
4468 debug("grub_fs_probe failed, %s\n", device_name);
4469 goto end;
4470 }
4471
4472 fs->fs_dir(dev, args[1], hook, name);
4473 if (name[0])
4474 {
4475 ventoy_set_env(args[2], name);
4476 }
4477
4478 rc = 0;
4479
4480 end:
4481
4482 check_free(device_name, grub_free);
4483 check_free(dev, grub_device_close);
4484
4485 return rc;
4486 }
4487
4488 static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args)
4489 {
4490 (void)ctxt;
4491 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file);
4492 }
4493
4494 static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args)
4495 {
4496 (void)ctxt;
4497 return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir);
4498 }
4499
4500 static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args)
4501 {
4502 char c;
4503 char *pos = NULL;
4504 char *end = NULL;
4505
4506 (void)ctxt;
4507
4508 if (argc != 2)
4509 {
4510 debug("ventoy_cmd_basename, invalid param num %d\n", argc);
4511 return 1;
4512 }
4513
4514 for (pos = args[0]; *pos; pos++)
4515 {
4516 if (*pos == '.')
4517 {
4518 end = pos;
4519 }
4520 }
4521
4522 if (end)
4523 {
4524 c = *end;
4525 *end = 0;
4526 }
4527
4528 grub_env_set(args[1], args[0]);
4529
4530 if (end)
4531 {
4532 *end = c;
4533 }
4534
4535 return 0;
4536 }
4537
4538 static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args)
4539 {
4540 int i;
4541 int len;
4542 const char *buf;
4543
4544 (void)ctxt;
4545
4546 if (argc != 2)
4547 {
4548 debug("ventoy_cmd_basefile, invalid param num %d\n", argc);
4549 return 1;
4550 }
4551
4552 buf = args[0];
4553 len = (int)grub_strlen(buf);
4554 for (i = len; i > 0; i--)
4555 {
4556 if (buf[i - 1] == '/')
4557 {
4558 grub_env_set(args[1], buf + i);
4559 return 0;
4560 }
4561 }
4562
4563 grub_env_set(args[1], buf);
4564
4565 return 0;
4566 }
4567
4568 static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4569 {
4570 struct grub_video_mode_info info;
4571 char buf[32];
4572
4573 (void)ctxt;
4574 (void)argc;
4575 (void)args;
4576
4577 if (!g_video_mode_list)
4578 {
4579 ventoy_enum_video_mode();
4580 }
4581
4582 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4583 {
4584 grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height);
4585 }
4586 else
4587 {
4588 grub_snprintf(buf, sizeof(buf), "Resolution (0x0)");
4589 }
4590
4591 grub_env_set("VTOY_CUR_VIDEO_MODE", buf);
4592
4593 grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num);
4594 grub_env_set("VTOY_VIDEO_MODE_NUM", buf);
4595
4596 VENTOY_CMD_RETURN(0);
4597 }
4598
4599 static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4600 {
4601 struct grub_video_mode_info info;
4602 char buf[32];
4603
4604 (void)ctxt;
4605 (void)argc;
4606 (void)args;
4607
4608 if (grub_video_get_info(&info) == GRUB_ERR_NONE)
4609 {
4610 grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp);
4611 }
4612 else
4613 {
4614 grub_snprintf(buf, sizeof(buf), "0x0x0");
4615 }
4616
4617 grub_env_set(args[0], buf);
4618
4619 VENTOY_CMD_RETURN(0);
4620 }
4621
4622 static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args)
4623 {
4624 int id;
4625 char buf[32];
4626
4627 (void)ctxt;
4628 (void)argc;
4629
4630 if (!g_video_mode_list)
4631 {
4632 return 0;
4633 }
4634
4635 id = (int)grub_strtoul(args[0], NULL, 10);
4636 if (id < g_video_mode_num)
4637 {
4638 grub_snprintf(buf, sizeof(buf), "%ux%ux%u",
4639 g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp);
4640 }
4641
4642 grub_env_set(args[1], buf);
4643
4644 VENTOY_CMD_RETURN(0);
4645 }
4646
4647 static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args)
4648 {
4649 grub_uint32_t i;
4650 grub_uint32_t loadsector = 0;
4651 grub_file_t file;
4652 char value[32];
4653 grub_uint32_t boot_catlog = 0;
4654 grub_uint8_t buf[512];
4655
4656 (void)ctxt;
4657
4658 if (argc != 2)
4659 {
4660 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc);
4661 return 1;
4662 }
4663
4664 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
4665 if (!file)
4666 {
4667 debug("failed to open %s\n", args[0]);
4668 return 1;
4669 }
4670
4671 boot_catlog = ventoy_get_iso_boot_catlog(file);
4672 if (boot_catlog == 0)
4673 {
4674 debug("No bootcatlog found\n");
4675 grub_file_close(file);
4676 return 1;
4677 }
4678
4679 grub_memset(buf, 0, sizeof(buf));
4680 grub_file_seek(file, boot_catlog * 2048);
4681 grub_file_read(file, buf, sizeof(buf));
4682 grub_file_close(file);
4683
4684 for (i = 0; i < sizeof(buf); i += 32)
4685 {
4686 if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF)
4687 {
4688 if (buf[i + 32] == 0x88)
4689 {
4690 loadsector = *(grub_uint32_t *)(buf + i + 32 + 8);
4691 grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512
4692 break;
4693 }
4694 }
4695 }
4696
4697 if (loadsector == 0)
4698 {
4699 debug("No EFI eltorito info found\n");
4700 return 1;
4701 }
4702
4703 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value);
4704 grub_env_set(args[1], value);
4705 VENTOY_CMD_RETURN(0);
4706 }
4707
4708 static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data)
4709 {
4710 int curpos;
4711 int printlen;
4712 grub_size_t len;
4713 replace_fs_dir *pfsdir = (replace_fs_dir *)data;
4714
4715 if (pfsdir->initrd[0])
4716 {
4717 return 1;
4718 }
4719
4720 curpos = pfsdir->curpos;
4721 len = grub_strlen(filename);
4722
4723 if (info->dir)
4724 {
4725 if ((len == 1 && filename[0] == '.') ||
4726 (len == 2 && filename[0] == '.' && filename[1] == '.'))
4727 {
4728 return 0;
4729 }
4730
4731 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4732 pfsdir->dircnt++;
4733
4734 printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename);
4735 pfsdir->curpos = curpos + printlen;
4736 pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir);
4737 pfsdir->curpos = curpos;
4738 pfsdir->fullpath[curpos] = 0;
4739 }
4740 else
4741 {
4742 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4743 pfsdir->filecnt++;
4744
4745 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4746 if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0)
4747 {
4748 if (info->size > 32 * VTOY_SIZE_1MB)
4749 {
4750 grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename);
4751 return 1;
4752 }
4753 }
4754 }
4755
4756 return 0;
4757 }
4758
4759 static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args)
4760 {
4761 int i;
4762 char *pos = NULL;
4763 char *device_name = NULL;
4764 grub_device_t dev = NULL;
4765 grub_fs_t fs = NULL;
4766 replace_fs_dir *pfsdir = NULL;
4767
4768 (void)ctxt;
4769
4770 if (argc != 2)
4771 {
4772 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc);
4773 return 1;
4774 }
4775
4776 pfsdir = grub_zalloc(sizeof(replace_fs_dir));
4777 if (!pfsdir)
4778 {
4779 return 1;
4780 }
4781
4782 device_name = grub_file_get_device_name(args[0]);
4783 if (!device_name)
4784 {
4785 goto fail;
4786 }
4787
4788 dev = grub_device_open(device_name);
4789 if (!dev)
4790 {
4791 goto fail;
4792 }
4793
4794 fs = grub_fs_probe(dev);
4795 if (!fs)
4796 {
4797 goto fail;
4798 }
4799
4800 pfsdir->dev = dev;
4801 pfsdir->fs = fs;
4802 pfsdir->curpos = 1;
4803 pfsdir->fullpath[0] = '/';
4804 fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir);
4805
4806 if (pfsdir->initrd[0])
4807 {
4808 debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt);
4809
4810 for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++)
4811 {
4812 if (pfsdir->initrd[i] == '/')
4813 {
4814 pfsdir->initrd[i] = '\\';
4815 }
4816 }
4817
4818 pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd;
4819 grub_env_set(args[1], pos);
4820 }
4821 else
4822 {
4823 debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt);
4824 }
4825
4826 fail:
4827
4828 grub_check_free(pfsdir);
4829 grub_check_free(device_name);
4830 check_free(dev, grub_device_close);
4831
4832 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4833 }
4834
4835 static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4836 {
4837 const char *pager = NULL;
4838
4839 (void)ctxt;
4840 (void)argc;
4841 (void)args;
4842
4843 pager = grub_env_get("pager");
4844 if (NULL == pager)
4845 {
4846 g_pager_flag = 1;
4847 grub_env_set("pager", "1");
4848 }
4849 else if (pager[0] == '1')
4850 {
4851 g_pager_flag = 0;
4852 }
4853 else
4854 {
4855 grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager);
4856 g_pager_flag = 2;
4857 grub_env_set("pager", "1");
4858 }
4859
4860 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4861 }
4862
4863 static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args)
4864 {
4865 (void)ctxt;
4866 (void)argc;
4867 (void)args;
4868
4869 if (g_pager_flag == 1)
4870 {
4871 grub_env_unset("pager");
4872 }
4873 else if (g_pager_flag == 2)
4874 {
4875 grub_env_set("pager", g_old_pager);
4876 }
4877
4878 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4879 }
4880
4881 static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data)
4882 {
4883 if (g_json_case_mis_path[0])
4884 {
4885 return 1;
4886 }
4887
4888 if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0)
4889 {
4890 grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename);
4891 return 1;
4892 }
4893 return 0;
4894 }
4895
4896 static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data)
4897 {
4898 char path[16];
4899 chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data;
4900
4901 if (g_json_case_mis_path[0])
4902 {
4903 return 1;
4904 }
4905
4906 if (info->dir && (filename[0] == 'v' || filename[0] == 'V'))
4907 {
4908 if (grub_strcasecmp(filename, "ventoy") == 0)
4909 {
4910 grub_snprintf(path, sizeof(path), "/%s", filename);
4911 fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path);
4912 if (g_json_case_mis_path[0])
4913 {
4914 return 1;
4915 }
4916 }
4917 }
4918
4919 return 0;
4920 }
4921
4922 static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args)
4923 {
4924 int fstype = 0;
4925 char *device_name = NULL;
4926 grub_device_t dev = NULL;
4927 grub_fs_t fs = NULL;
4928 chk_case_fs_dir fs_dir;
4929
4930 (void)ctxt;
4931 (void)argc;
4932 (void)args;
4933
4934 device_name = grub_file_get_device_name(args[0]);
4935 if (!device_name)
4936 {
4937 goto out;
4938 }
4939
4940 dev = grub_device_open(device_name);
4941 if (!dev)
4942 {
4943 goto out;
4944 }
4945
4946 fs = grub_fs_probe(dev);
4947 if (!fs)
4948 {
4949 goto out;
4950 }
4951
4952 fstype = ventoy_get_fs_type(fs->name);
4953 if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max)
4954 {
4955 goto out;
4956 }
4957
4958 g_json_case_mis_path[0] = 0;
4959 fs_dir.dev = dev;
4960 fs_dir.fs = fs;
4961 fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir);
4962
4963 if (g_json_case_mis_path[0])
4964 {
4965 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path);
4966 }
4967
4968 out:
4969
4970 grub_check_free(device_name);
4971 check_free(dev, grub_device_close);
4972
4973 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
4974 }
4975
4976 static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args)
4977 {
4978 grub_disk_t disk;
4979 grub_partition_t part;
4980 char priority_str[3]; /* Maximum value 15 */
4981
4982 (void)ctxt;
4983
4984 if (argc < 2 || argc > 3)
4985 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4986 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
4987
4988 /* Open the disk if it exists */
4989 disk = grub_disk_open (args[0]);
4990 if (!disk)
4991 {
4992 return grub_error (GRUB_ERR_BAD_ARGUMENT,
4993 "Not a disk");
4994 }
4995
4996 part = grub_partition_probe (disk, args[1]);
4997 if (!part)
4998 {
4999 grub_disk_close (disk);
5000 return grub_error (GRUB_ERR_BAD_ARGUMENT,
5001 "No such partition");
5002 }
5003
5004 if (grub_strcmp (part->partmap->name, "gpt"))
5005 {
5006 grub_disk_close (disk);
5007 return grub_error (GRUB_ERR_BAD_PART_TABLE,
5008 "Not a GPT partition");
5009 }
5010
5011 grub_snprintf (priority_str, sizeof(priority_str), "%u",
5012 (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL));
5013
5014 if (argc == 3)
5015 {
5016 grub_env_set (args[2], priority_str);
5017 grub_env_export (args[2]);
5018 }
5019 else
5020 {
5021 grub_printf ("Priority is %s\n", priority_str);
5022 }
5023
5024 grub_disk_close (disk);
5025 return GRUB_ERR_NONE;
5026 }
5027
5028
5029 static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
5030 {
5031 int ret = 1;
5032 int joliet = 0;
5033 grub_file_t file = NULL;
5034 grub_uint32_t loadrba = 0;
5035 grub_uint32_t boot_catlog = 0;
5036 grub_uint8_t sector[512];
5037 boot_info_table *info = NULL;
5038
5039 (void)ctxt;
5040 (void)argc;
5041
5042 /* This also trigger a iso9660 fs parse */
5043 if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg"))
5044 {
5045 return 0;
5046 }
5047
5048 joliet = grub_iso9660_is_joliet();
5049 if (joliet == 0)
5050 {
5051 return 1;
5052 }
5053
5054 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
5055 if (!file)
5056 {
5057 debug("failed to open %s\n", args[0]);
5058 return 1;
5059 }
5060
5061 boot_catlog = ventoy_get_iso_boot_catlog(file);
5062 if (boot_catlog == 0)
5063 {
5064 debug("no bootcatlog found %u\n", boot_catlog);
5065 goto out;
5066 }
5067
5068 loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog);
5069 if (loadrba == 0)
5070 {
5071 debug("no bios eltorito rba found %u\n", loadrba);
5072 goto out;
5073 }
5074
5075 grub_file_seek(file, loadrba * 2048);
5076 grub_file_read(file, sector, 512);
5077
5078 info = (boot_info_table *)sector;
5079 if (info->bi_data0 == 0x7c6ceafa &&
5080 info->bi_data1 == 0x90900000 &&
5081 info->bi_PrimaryVolumeDescriptor == 16 &&
5082 info->bi_BootFileLocation == loadrba)
5083 {
5084 debug("bootloader is syslinux, %u.\n", loadrba);
5085 ret = 0;
5086 }
5087
5088 out:
5089
5090 grub_file_close(file);
5091 grub_errno = GRUB_ERR_NONE;
5092 return ret;
5093 }
5094
5095 int ventoy_env_init(void)
5096 {
5097 char buf[64];
5098
5099 grub_env_set("vtdebug_flag", "");
5100
5101 g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN);
5102 g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5103 g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
5104 g_conf_replace_new_buf = grub_malloc(vtoy_max_replace_file_size);
5105
5106 ventoy_filt_register(0, ventoy_wrapper_open);
5107
5108 g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
5109 if (g_grub_param)
5110 {
5111 g_grub_param->grub_env_get = grub_env_get;
5112 g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set;
5113 g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf;
5114 grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
5115 grub_env_set("env_param", buf);
5116 grub_env_set("ventoy_env_param", buf);
5117
5118 grub_env_export("env_param");
5119 grub_env_export("ventoy_env_param");
5120 }
5121
5122 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)g_vtoy_winpeshl_ini);
5123 grub_env_set("vtoy_winpeshl_ini_addr", buf);
5124
5125 grub_snprintf(buf, sizeof(buf), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini));
5126 grub_env_set("vtoy_winpeshl_ini_size", buf);
5127
5128 grub_env_export("vtoy_winpeshl_ini_addr");
5129 grub_env_export("vtoy_winpeshl_ini_size");
5130
5131 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size);
5132 grub_env_set("vtoy_chain_file_size", buf);
5133 grub_env_export("vtoy_chain_file_size");
5134
5135 grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read);
5136 grub_env_set("vtoy_chain_file_read", buf);
5137 grub_env_export("vtoy_chain_file_read");
5138
5139 return 0;
5140 }
5141
5142
5143
5144 static cmd_para ventoy_cmds[] =
5145 {
5146 { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
5147 { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL },
5148 { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
5149 { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
5150 { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL },
5151 { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5152 { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
5153 { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
5154 { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL },
5155 { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL },
5156 { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL },
5157 { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL },
5158 { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL },
5159 { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL },
5160 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
5161 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL },
5162 { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
5163 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
5164 { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
5165 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL },
5166 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL },
5167 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL },
5168 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL },
5169 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL },
5170 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL },
5171
5172 { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL },
5173 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL },
5174 { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
5175 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
5176 { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL },
5177 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL },
5178 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL },
5179
5180 { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL },
5181 { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL },
5182 { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL },
5183 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL },
5184 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL },
5185 { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL },
5186 { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL },
5187 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL },
5188 { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL },
5189 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL },
5190
5191
5192 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
5193 { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
5194 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
5195 { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
5196 { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL },
5197 { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL },
5198 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
5199 { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
5200 { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
5201 { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
5202 { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL },
5203
5204 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
5205 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL },
5206 { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
5207 { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
5208 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
5209 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
5210 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
5211
5212 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5213 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
5214 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL },
5215 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
5216 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
5217 { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
5218 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
5219 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
5220 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
5221 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL },
5222
5223 { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
5224 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
5225 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL },
5226 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL },
5227 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL },
5228 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL },
5229 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL },
5230 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL },
5231 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
5232
5233 { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
5234 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL },
5235 { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
5236 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL },
5237
5238
5239 { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
5240 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL },
5241 { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL },
5242
5243 { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL },
5244 { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL },
5245 { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL },
5246
5247
5248 { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL },
5249 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL },
5250 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL },
5251 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL },
5252 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL },
5253 { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL },
5254 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL },
5255 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
5256 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL },
5257 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL },
5258 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
5259
5260 { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
5261 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
5262 { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL },
5263 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL },
5264 { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL },
5265 { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
5266 { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
5267 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
5268 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
5269 { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL },
5270
5271 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL },
5272 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL },
5273 { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL },
5274 { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL },
5275 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL },
5276 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL },
5277 { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL },
5278 { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL },
5279 };
5280
5281 int ventoy_register_all_cmd(void)
5282 {
5283 grub_uint32_t i;
5284 cmd_para *cur = NULL;
5285
5286 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5287 {
5288 cur = ventoy_cmds + i;
5289 cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags,
5290 cur->summary, cur->description, cur->parser);
5291 }
5292
5293 return 0;
5294 }
5295
5296 int ventoy_unregister_all_cmd(void)
5297 {
5298 grub_uint32_t i;
5299
5300 for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++)
5301 {
5302 grub_unregister_extcmd(ventoy_cmds[i].cmd);
5303 }
5304
5305 return 0;
5306 }
5307
5308