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