]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
426e75fc051f81ebafdc1213ff0e2b54a87ad0fe
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_plugin.c
1 /******************************************************************************
2 * ventoy_plugin.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20 #include <grub/types.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/err.h>
24 #include <grub/dl.h>
25 #include <grub/disk.h>
26 #include <grub/device.h>
27 #include <grub/term.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/normal.h>
31 #include <grub/extcmd.h>
32 #include <grub/datetime.h>
33 #include <grub/i18n.h>
34 #include <grub/net.h>
35 #include <grub/time.h>
36 #include <grub/font.h>
37 #include <grub/ventoy.h>
38 #include "ventoy_def.h"
39
40 GRUB_MOD_LICENSE ("GPLv3+");
41
42 static char g_iso_disk_name[128];
43 static install_template *g_install_template_head = NULL;
44 static persistence_config *g_persistence_head = NULL;
45 static menu_alias *g_menu_alias_head = NULL;
46 static menu_class *g_menu_class_head = NULL;
47 static injection_config *g_injection_head = NULL;
48
49 static int ventoy_plugin_control_check(VTOY_JSON *json, const char *isodisk)
50 {
51 int rc = 0;
52 VTOY_JSON *pNode = NULL;
53 VTOY_JSON *pChild = NULL;
54
55 (void)isodisk;
56
57 if (json->enDataType != JSON_TYPE_ARRAY)
58 {
59 grub_printf("Not array type %d\n", json->enDataType);
60 return 1;
61 }
62
63 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
64 {
65 if (pNode->enDataType == JSON_TYPE_OBJECT)
66 {
67 pChild = pNode->pstChild;
68 if (pChild->enDataType == JSON_TYPE_STRING)
69 {
70 grub_printf("%s: %s\n", pChild->pcName, pChild->unData.pcStrVal);
71 }
72 else
73 {
74 grub_printf("%s is NOT string type\n", pChild->pcName);
75 rc = 1;
76 }
77 }
78 else
79 {
80 grub_printf("%s is not an object\n", pNode->pcName);
81 rc = 1;
82 }
83 }
84
85 return rc;
86 }
87
88 static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
89 {
90 VTOY_JSON *pNode = NULL;
91 VTOY_JSON *pChild = NULL;
92
93 (void)isodisk;
94
95 if (json->enDataType != JSON_TYPE_ARRAY)
96 {
97 debug("Not array %d\n", json->enDataType);
98 return 0;
99 }
100
101 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
102 {
103 if (pNode->enDataType == JSON_TYPE_OBJECT)
104 {
105 pChild = pNode->pstChild;
106 if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal)
107 {
108 ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal);
109 }
110 }
111 }
112
113 return 0;
114 }
115
116 static int ventoy_plugin_theme_check(VTOY_JSON *json, const char *isodisk)
117 {
118 int exist = 0;
119 const char *value;
120 VTOY_JSON *node;
121
122 value = vtoy_json_get_string_ex(json->pstChild, "file");
123 if (value)
124 {
125 grub_printf("file: %s\n", value);
126 if (value[0] == '/')
127 {
128 exist = ventoy_is_file_exist("%s%s", isodisk, value);
129 }
130 else
131 {
132 exist = ventoy_is_file_exist("%s/ventoy/%s", isodisk, value);
133 }
134
135 if (exist == 0)
136 {
137 grub_printf("Theme file %s does NOT exist\n", value);
138 return 1;
139 }
140 }
141
142 value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
143 if (value)
144 {
145 grub_printf("gfxmode: %s\n", value);
146 }
147
148 value = vtoy_json_get_string_ex(json->pstChild, "display_mode");
149 if (value)
150 {
151 grub_printf("display_mode: %s\n", value);
152 }
153
154 value = vtoy_json_get_string_ex(json->pstChild, "serial_param");
155 if (value)
156 {
157 grub_printf("serial_param %s\n", value);
158 }
159
160 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
161 if (value)
162 {
163 grub_printf("ventoy_left: %s\n", value);
164 }
165
166 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top");
167 if (value)
168 {
169 grub_printf("ventoy_top: %s\n", value);
170 }
171
172 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color");
173 if (value)
174 {
175 grub_printf("ventoy_color: %s\n", value);
176 }
177
178 node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts");
179 if (node)
180 {
181 for (node = node->pstChild; node; node = node->pstNext)
182 {
183 if (node->enDataType == JSON_TYPE_STRING)
184 {
185 if (ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal))
186 {
187 grub_printf("%s [OK]\n", node->unData.pcStrVal);
188 }
189 else
190 {
191 grub_printf("%s [NOT EXIST]\n", node->unData.pcStrVal);
192 }
193 }
194 }
195 }
196 else
197 {
198 grub_printf("fonts NOT found\n");
199 }
200
201 return 0;
202 }
203
204 static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
205 {
206 const char *value;
207 char filepath[256];
208 VTOY_JSON *node;
209
210 value = vtoy_json_get_string_ex(json->pstChild, "file");
211 if (value)
212 {
213 if (value[0] == '/')
214 {
215 grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value);
216 }
217 else
218 {
219 grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value);
220 }
221
222 if (ventoy_is_file_exist(filepath) == 0)
223 {
224 debug("Theme file %s does not exist\n", filepath);
225 return 0;
226 }
227
228 debug("vtoy_theme %s\n", filepath);
229 grub_env_set("vtoy_theme", filepath);
230 }
231
232 value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
233 if (value)
234 {
235 debug("vtoy_gfxmode %s\n", value);
236 grub_env_set("vtoy_gfxmode", value);
237 }
238
239 value = vtoy_json_get_string_ex(json->pstChild, "display_mode");
240 if (value)
241 {
242 debug("display_mode %s\n", value);
243 grub_env_set("vtoy_display_mode", value);
244 }
245
246 value = vtoy_json_get_string_ex(json->pstChild, "serial_param");
247 if (value)
248 {
249 debug("serial_param %s\n", value);
250 grub_env_set("vtoy_serial_param", value);
251 }
252
253 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
254 if (value)
255 {
256 grub_env_set("VTLE_LFT", value);
257 }
258
259 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top");
260 if (value)
261 {
262 grub_env_set("VTLE_TOP", value);
263 }
264
265 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color");
266 if (value)
267 {
268 grub_env_set("VTLE_CLR", value);
269 }
270
271 node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts");
272 if (node)
273 {
274 for (node = node->pstChild; node; node = node->pstNext)
275 {
276 if (node->enDataType == JSON_TYPE_STRING &&
277 ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal))
278 {
279 grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, node->unData.pcStrVal);
280 grub_font_load(filepath);
281 }
282 }
283 }
284
285 return 0;
286 }
287
288 static int ventoy_plugin_check_path(const char *path, const char *file)
289 {
290 if (file[0] != '/')
291 {
292 grub_printf("%s is NOT begin with '/' \n", file);
293 return 1;
294 }
295
296 if (grub_strchr(file, '\\'))
297 {
298 grub_printf("%s contains invalid '\\' \n", file);
299 return 1;
300 }
301
302 if (grub_strstr(file, "//"))
303 {
304 grub_printf("%s contains invalid double slash\n", file);
305 return 1;
306 }
307
308 if (grub_strstr(file, "../"))
309 {
310 grub_printf("%s contains invalid '../' \n", file);
311 return 1;
312 }
313
314 if (!ventoy_is_file_exist("%s%s", path, file))
315 {
316 grub_printf("%s%s does NOT exist\n", path, file);
317 return 1;
318 }
319
320 return 0;
321 }
322
323 static int ventoy_plugin_check_fullpath
324 (
325 VTOY_JSON *json,
326 const char *isodisk,
327 const char *key,
328 int *pathnum
329 )
330 {
331 int rc = 0;
332 int ret = 0;
333 int cnt = 0;
334 VTOY_JSON *node = json;
335 VTOY_JSON *child = NULL;
336
337 while (node)
338 {
339 if (0 == grub_strcmp(key, node->pcName))
340 {
341 break;
342 }
343 node = node->pstNext;
344 }
345
346 if (!node)
347 {
348 return 1;
349 }
350
351 if (JSON_TYPE_STRING == node->enDataType)
352 {
353 cnt = 1;
354 ret = ventoy_plugin_check_path(isodisk, node->unData.pcStrVal);
355 grub_printf("%s: %s [%s]\n", key, node->unData.pcStrVal, ret ? "FAIL" : "OK");
356 }
357 else if (JSON_TYPE_ARRAY == node->enDataType)
358 {
359 for (child = node->pstChild; child; child = child->pstNext)
360 {
361 if (JSON_TYPE_STRING != child->enDataType)
362 {
363 grub_printf("Non string json type\n");
364 }
365 else
366 {
367 rc = ventoy_plugin_check_path(isodisk, child->unData.pcStrVal);
368 grub_printf("%s: %s [%s]\n", key, child->unData.pcStrVal, rc ? "FAIL" : "OK");
369 ret += rc;
370 cnt++;
371 }
372 }
373 }
374
375 *pathnum = cnt;
376 return ret;
377 }
378
379 static int ventoy_plugin_parse_fullpath
380 (
381 VTOY_JSON *json,
382 const char *isodisk,
383 const char *key,
384 file_fullpath **fullpath,
385 int *pathnum
386 )
387 {
388 int rc = 1;
389 int count = 0;
390 VTOY_JSON *node = json;
391 VTOY_JSON *child = NULL;
392 file_fullpath *path = NULL;
393
394 while (node)
395 {
396 if (0 == grub_strcmp(key, node->pcName))
397 {
398 break;
399 }
400 node = node->pstNext;
401 }
402
403 if (!node)
404 {
405 return 1;
406 }
407
408 if (JSON_TYPE_STRING == node->enDataType)
409 {
410 debug("%s is string type data\n", node->pcName);
411
412 if ((node->unData.pcStrVal[0] != '/') || (!ventoy_is_file_exist("%s%s", isodisk, node->unData.pcStrVal)))
413 {
414 debug("%s%s file not found\n", isodisk, node->unData.pcStrVal);
415 return 1;
416 }
417
418 path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath));
419 if (path)
420 {
421 grub_snprintf(path->path, sizeof(path->path), "%s", node->unData.pcStrVal);
422 *fullpath = path;
423 *pathnum = 1;
424 rc = 0;
425 }
426 }
427 else if (JSON_TYPE_ARRAY == node->enDataType)
428 {
429 for (child = node->pstChild; child; child = child->pstNext)
430 {
431 if ((JSON_TYPE_STRING != child->enDataType) || (child->unData.pcStrVal[0] != '/'))
432 {
433 debug("Invalid data type:%d\n", child->enDataType);
434 return 1;
435 }
436 count++;
437 }
438 debug("%s is array type data, count=%d\n", node->pcName, count);
439
440 path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath) * count);
441 if (path)
442 {
443 *fullpath = path;
444
445 for (count = 0, child = node->pstChild; child; child = child->pstNext)
446 {
447 if (ventoy_is_file_exist("%s%s", isodisk, child->unData.pcStrVal))
448 {
449 grub_snprintf(path->path, sizeof(path->path), "%s", child->unData.pcStrVal);
450 path++;
451 count++;
452 }
453 }
454
455 *pathnum = count;
456 rc = 0;
457 }
458 }
459
460 return rc;
461 }
462
463 static int ventoy_plugin_auto_install_check(VTOY_JSON *json, const char *isodisk)
464 {
465 int pathnum = 0;
466 int autosel = 0;
467 const char *iso = NULL;
468 VTOY_JSON *pNode = NULL;
469
470 if (json->enDataType != JSON_TYPE_ARRAY)
471 {
472 grub_printf("Not array type %d\n", json->enDataType);
473 return 1;
474 }
475
476 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
477 {
478 if (pNode->enDataType != JSON_TYPE_OBJECT)
479 {
480 grub_printf("NOT object type\n");
481 }
482
483 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
484 if (iso)
485 {
486 if (0 == ventoy_plugin_check_path(isodisk, iso))
487 {
488 grub_printf("image: %s [OK]\n", iso);
489 ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "template", &pathnum);
490
491 if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel))
492 {
493 if (autosel >= 0 && autosel <= pathnum)
494 {
495 grub_printf("autosel: %d [OK]\n", autosel);
496 }
497 else
498 {
499 grub_printf("autosel: %d [FAIL]\n", autosel);
500 }
501 }
502 }
503 else
504 {
505 grub_printf("image: %s [FAIL]\n", iso);
506 }
507 }
508 else
509 {
510 grub_printf("image not found\n");
511 }
512 }
513
514 return 0;
515 }
516
517 static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk)
518 {
519 int pathnum = 0;
520 int autosel = 0;
521 const char *iso = NULL;
522 VTOY_JSON *pNode = NULL;
523 install_template *node = NULL;
524 install_template *next = NULL;
525 file_fullpath *templatepath = NULL;
526
527 if (json->enDataType != JSON_TYPE_ARRAY)
528 {
529 debug("Not array %d\n", json->enDataType);
530 return 0;
531 }
532
533 if (g_install_template_head)
534 {
535 for (node = g_install_template_head; node; node = next)
536 {
537 next = node->next;
538 grub_check_free(node->templatepath);
539 grub_free(node);
540 }
541
542 g_install_template_head = NULL;
543 }
544
545 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
546 {
547 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
548 if (iso && iso[0] == '/')
549 {
550 if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "template", &templatepath, &pathnum))
551 {
552 node = grub_zalloc(sizeof(install_template));
553 if (node)
554 {
555 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
556 node->templatepath = templatepath;
557 node->templatenum = pathnum;
558
559 node->autosel = -1;
560 if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel))
561 {
562 if (autosel >= 0 && autosel <= pathnum)
563 {
564 node->autosel = autosel;
565 }
566 }
567
568 if (g_install_template_head)
569 {
570 node->next = g_install_template_head;
571 }
572
573 g_install_template_head = node;
574 }
575 }
576 }
577 }
578
579 return 0;
580 }
581
582 static int ventoy_plugin_persistence_check(VTOY_JSON *json, const char *isodisk)
583 {
584 int autosel = 0;
585 int pathnum = 0;
586 const char *iso = NULL;
587 VTOY_JSON *pNode = NULL;
588
589 if (json->enDataType != JSON_TYPE_ARRAY)
590 {
591 grub_printf("Not array type %d\n", json->enDataType);
592 return 1;
593 }
594
595 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
596 {
597 if (pNode->enDataType != JSON_TYPE_OBJECT)
598 {
599 grub_printf("NOT object type\n");
600 }
601
602 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
603 if (iso)
604 {
605 if (0 == ventoy_plugin_check_path(isodisk, iso))
606 {
607 grub_printf("image: %s [OK]\n", iso);
608 ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "backend", &pathnum);
609
610 if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel))
611 {
612 if (autosel >= 0 && autosel <= pathnum)
613 {
614 grub_printf("autosel: %d [OK]\n", autosel);
615 }
616 else
617 {
618 grub_printf("autosel: %d [FAIL]\n", autosel);
619 }
620 }
621 }
622 else
623 {
624 grub_printf("image: %s [FAIL]\n", iso);
625 }
626 }
627 else
628 {
629 grub_printf("image not found\n");
630 }
631 }
632
633 return 0;
634 }
635
636 static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk)
637 {
638 int autosel = 0;
639 int pathnum = 0;
640 const char *iso = NULL;
641 VTOY_JSON *pNode = NULL;
642 persistence_config *node = NULL;
643 persistence_config *next = NULL;
644 file_fullpath *backendpath = NULL;
645
646 (void)isodisk;
647
648 if (json->enDataType != JSON_TYPE_ARRAY)
649 {
650 debug("Not array %d\n", json->enDataType);
651 return 0;
652 }
653
654 if (g_persistence_head)
655 {
656 for (node = g_persistence_head; node; node = next)
657 {
658 next = node->next;
659 grub_check_free(node->backendpath);
660 grub_free(node);
661 }
662
663 g_persistence_head = NULL;
664 }
665
666 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
667 {
668 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
669 if (iso && iso[0] == '/')
670 {
671 if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "backend", &backendpath, &pathnum))
672 {
673 node = grub_zalloc(sizeof(persistence_config));
674 if (node)
675 {
676 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
677 node->backendpath = backendpath;
678 node->backendnum = pathnum;
679
680 node->autosel = -1;
681 if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel))
682 {
683 if (autosel >= 0 && autosel <= pathnum)
684 {
685 node->autosel = autosel;
686 }
687 }
688
689 if (g_persistence_head)
690 {
691 node->next = g_persistence_head;
692 }
693
694 g_persistence_head = node;
695 }
696 }
697 }
698 }
699
700 return 0;
701 }
702
703 static int ventoy_plugin_menualias_check(VTOY_JSON *json, const char *isodisk)
704 {
705 int type;
706 const char *path = NULL;
707 const char *alias = NULL;
708 VTOY_JSON *pNode = NULL;
709
710 (void)isodisk;
711
712 if (json->enDataType != JSON_TYPE_ARRAY)
713 {
714 grub_printf("Not array %d\n", json->enDataType);
715 return 1;
716 }
717
718 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
719 {
720 type = vtoy_alias_image_file;
721 path = vtoy_json_get_string_ex(pNode->pstChild, "image");
722 if (!path)
723 {
724 path = vtoy_json_get_string_ex(pNode->pstChild, "dir");
725 type = vtoy_alias_directory;
726 }
727
728 alias = vtoy_json_get_string_ex(pNode->pstChild, "alias");
729 if (path && path[0] == '/' && alias)
730 {
731 if (vtoy_alias_image_file == type)
732 {
733 if (ventoy_is_file_exist("%s%s", isodisk, path))
734 {
735 grub_printf("image: <%s> [ OK ]\n", path);
736 }
737 else
738 {
739 grub_printf("image: <%s> [ NOT EXIST ]\n", path);
740 }
741 }
742 else
743 {
744 if (ventoy_is_dir_exist("%s%s", isodisk, path))
745 {
746 grub_printf("dir: <%s> [ OK ]\n", path);
747 }
748 else
749 {
750 grub_printf("dir: <%s> [ NOT EXIST ]\n", path);
751 }
752 }
753
754 grub_printf("alias: <%s>\n\n", alias);
755 }
756 }
757
758 return 0;
759 }
760
761 static int ventoy_plugin_menualias_entry(VTOY_JSON *json, const char *isodisk)
762 {
763 int type;
764 const char *path = NULL;
765 const char *alias = NULL;
766 VTOY_JSON *pNode = NULL;
767 menu_alias *node = NULL;
768 menu_alias *next = NULL;
769
770 (void)isodisk;
771
772 if (json->enDataType != JSON_TYPE_ARRAY)
773 {
774 debug("Not array %d\n", json->enDataType);
775 return 0;
776 }
777
778 if (g_menu_alias_head)
779 {
780 for (node = g_menu_alias_head; node; node = next)
781 {
782 next = node->next;
783 grub_free(node);
784 }
785
786 g_menu_alias_head = NULL;
787 }
788
789 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
790 {
791 type = vtoy_alias_image_file;
792 path = vtoy_json_get_string_ex(pNode->pstChild, "image");
793 if (!path)
794 {
795 path = vtoy_json_get_string_ex(pNode->pstChild, "dir");
796 type = vtoy_alias_directory;
797 }
798
799 alias = vtoy_json_get_string_ex(pNode->pstChild, "alias");
800 if (path && path[0] == '/' && alias)
801 {
802 node = grub_zalloc(sizeof(menu_alias));
803 if (node)
804 {
805 node->type = type;
806 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path);
807 grub_snprintf(node->alias, sizeof(node->alias), "%s", alias);
808
809 if (g_menu_alias_head)
810 {
811 node->next = g_menu_alias_head;
812 }
813
814 g_menu_alias_head = node;
815 }
816 }
817 }
818
819 return 0;
820 }
821
822
823 static int ventoy_plugin_injection_check(VTOY_JSON *json, const char *isodisk)
824 {
825 const char *path = NULL;
826 const char *archive = NULL;
827 VTOY_JSON *pNode = NULL;
828
829 (void)isodisk;
830
831 if (json->enDataType != JSON_TYPE_ARRAY)
832 {
833 grub_printf("Not array %d\n", json->enDataType);
834 return 0;
835 }
836
837 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
838 {
839 path = vtoy_json_get_string_ex(pNode->pstChild, "image");
840 if (!path)
841 {
842 grub_printf("image not found\n");
843 continue;
844 }
845
846 archive = vtoy_json_get_string_ex(pNode->pstChild, "archive");
847 if (!archive)
848 {
849 grub_printf("archive not found\n");
850 continue;
851 }
852
853 grub_printf("image: <%s> [%s]\n", path, ventoy_check_file_exist("%s%s", isodisk, path) ? "OK" : "NOT EXIST");
854 grub_printf("archive: <%s> [%s]\n\n", archive, ventoy_check_file_exist("%s%s", isodisk, archive) ? "OK" : "NOT EXIST");
855 }
856
857 return 0;
858 }
859
860 static int ventoy_plugin_injection_entry(VTOY_JSON *json, const char *isodisk)
861 {
862 const char *path = NULL;
863 const char *archive = NULL;
864 VTOY_JSON *pNode = NULL;
865 injection_config *node = NULL;
866 injection_config *next = NULL;
867
868 (void)isodisk;
869
870 if (json->enDataType != JSON_TYPE_ARRAY)
871 {
872 debug("Not array %d\n", json->enDataType);
873 return 0;
874 }
875
876 if (g_injection_head)
877 {
878 for (node = g_injection_head; node; node = next)
879 {
880 next = node->next;
881 grub_free(node);
882 }
883
884 g_injection_head = NULL;
885 }
886
887 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
888 {
889 path = vtoy_json_get_string_ex(pNode->pstChild, "image");
890 archive = vtoy_json_get_string_ex(pNode->pstChild, "archive");
891 if (path && path[0] == '/' && archive && archive[0] == '/')
892 {
893 node = grub_zalloc(sizeof(injection_config));
894 if (node)
895 {
896 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path);
897 grub_snprintf(node->archive, sizeof(node->archive), "%s", archive);
898
899 if (g_injection_head)
900 {
901 node->next = g_injection_head;
902 }
903
904 g_injection_head = node;
905 }
906 }
907 }
908
909 return 0;
910 }
911
912 static int ventoy_plugin_menuclass_entry(VTOY_JSON *json, const char *isodisk)
913 {
914 int type;
915 const char *key = NULL;
916 const char *class = NULL;
917 VTOY_JSON *pNode = NULL;
918 menu_class *tail = NULL;
919 menu_class *node = NULL;
920 menu_class *next = NULL;
921
922 (void)isodisk;
923
924 if (json->enDataType != JSON_TYPE_ARRAY)
925 {
926 debug("Not array %d\n", json->enDataType);
927 return 0;
928 }
929
930 if (g_menu_class_head)
931 {
932 for (node = g_menu_class_head; node; node = next)
933 {
934 next = node->next;
935 grub_free(node);
936 }
937
938 g_menu_class_head = NULL;
939 }
940
941 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
942 {
943 type = vtoy_class_image_file;
944 key = vtoy_json_get_string_ex(pNode->pstChild, "key");
945 if (!key)
946 {
947 key = vtoy_json_get_string_ex(pNode->pstChild, "dir");
948 type = vtoy_class_directory;
949 }
950
951 class = vtoy_json_get_string_ex(pNode->pstChild, "class");
952 if (key && class)
953 {
954 node = grub_zalloc(sizeof(menu_class));
955 if (node)
956 {
957 node->type = type;
958 node->patlen = grub_snprintf(node->pattern, sizeof(node->pattern), "%s", key);
959 grub_snprintf(node->class, sizeof(node->class), "%s", class);
960
961 if (g_menu_class_head)
962 {
963 tail->next = node;
964 }
965 else
966 {
967 g_menu_class_head = node;
968 }
969 tail = node;
970 }
971 }
972 }
973
974 return 0;
975 }
976
977 static int ventoy_plugin_menuclass_check(VTOY_JSON *json, const char *isodisk)
978 {
979 int type;
980 const char *key = NULL;
981 const char *class = NULL;
982 VTOY_JSON *pNode = NULL;
983
984 (void)isodisk;
985
986 if (json->enDataType != JSON_TYPE_ARRAY)
987 {
988 grub_printf("Not array %d\n", json->enDataType);
989 return 1;
990 }
991
992 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
993 {
994 type = vtoy_class_image_file;
995 key = vtoy_json_get_string_ex(pNode->pstChild, "key");
996 if (!key)
997 {
998 key = vtoy_json_get_string_ex(pNode->pstChild, "dir");
999 type = vtoy_class_directory;
1000 }
1001
1002 class = vtoy_json_get_string_ex(pNode->pstChild, "class");
1003 if (key && class)
1004 {
1005 grub_printf("%s: <%s>\n", (type == vtoy_class_directory) ? "dir" : "key", key);
1006 grub_printf("class: <%s>\n\n", class);
1007 }
1008 }
1009
1010 return 0;
1011 }
1012
1013 static plugin_entry g_plugin_entries[] =
1014 {
1015 { "control", ventoy_plugin_control_entry, ventoy_plugin_control_check },
1016 { "theme", ventoy_plugin_theme_entry, ventoy_plugin_theme_check },
1017 { "auto_install", ventoy_plugin_auto_install_entry, ventoy_plugin_auto_install_check },
1018 { "persistence", ventoy_plugin_persistence_entry, ventoy_plugin_persistence_check },
1019 { "menu_alias", ventoy_plugin_menualias_entry, ventoy_plugin_menualias_check },
1020 { "menu_class", ventoy_plugin_menuclass_entry, ventoy_plugin_menuclass_check },
1021 { "injection", ventoy_plugin_injection_entry, ventoy_plugin_injection_check },
1022 };
1023
1024 static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
1025 {
1026 int i;
1027 VTOY_JSON *cur = json;
1028
1029 grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk);
1030
1031 while (cur)
1032 {
1033 for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
1034 {
1035 if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0)
1036 {
1037 debug("Plugin entry for %s\n", g_plugin_entries[i].key);
1038 g_plugin_entries[i].entryfunc(cur, isodisk);
1039 break;
1040 }
1041 }
1042
1043 cur = cur->pstNext;
1044 }
1045
1046 return 0;
1047 }
1048
1049 grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args)
1050 {
1051 int ret = 0;
1052 char *buf = NULL;
1053 grub_file_t file;
1054 VTOY_JSON *json = NULL;
1055
1056 (void)ctxt;
1057 (void)argc;
1058
1059 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
1060 if (!file)
1061 {
1062 return GRUB_ERR_NONE;
1063 }
1064
1065 debug("json configuration file size %d\n", (int)file->size);
1066
1067 buf = grub_malloc(file->size + 1);
1068 if (!buf)
1069 {
1070 grub_file_close(file);
1071 return 1;
1072 }
1073
1074 buf[file->size] = 0;
1075 grub_file_read(file, buf, file->size);
1076 grub_file_close(file);
1077
1078 json = vtoy_json_create();
1079 if (!json)
1080 {
1081 return 1;
1082 }
1083
1084
1085
1086 ret = vtoy_json_parse(json, buf);
1087 if (ret)
1088 {
1089 debug("Failed to parse json string %d\n", ret);
1090 grub_free(buf);
1091 return 1;
1092 }
1093
1094 ventoy_parse_plugin_config(json->pstChild, args[0]);
1095
1096 vtoy_json_destroy(json);
1097
1098 grub_free(buf);
1099
1100 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1101 }
1102
1103 void ventoy_plugin_dump_injection(void)
1104 {
1105 injection_config *node = NULL;
1106
1107 for (node = g_injection_head; node; node = node->next)
1108 {
1109 grub_printf("\nIMAGE:<%s>\n", node->isopath);
1110 grub_printf("ARCHIVE:<%s>\n", node->archive);
1111 }
1112
1113 return;
1114 }
1115
1116
1117 void ventoy_plugin_dump_auto_install(void)
1118 {
1119 int i;
1120 install_template *node = NULL;
1121
1122 for (node = g_install_template_head; node; node = node->next)
1123 {
1124 grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->templatenum);
1125 for (i = 0; i < node->templatenum; i++)
1126 {
1127 grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path);
1128 }
1129 }
1130
1131 return;
1132 }
1133
1134 void ventoy_plugin_dump_persistence(void)
1135 {
1136 int rc;
1137 int i = 0;
1138 persistence_config *node = NULL;
1139 ventoy_img_chunk_list chunk_list;
1140
1141 for (node = g_persistence_head; node; node = node->next)
1142 {
1143 grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->backendnum);
1144
1145 for (i = 0; i < node->backendnum; i++)
1146 {
1147 grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path);
1148 rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list);
1149 if (rc == 0)
1150 {
1151 grub_printf(" [ SUCCESS ]\n");
1152 grub_free(chunk_list.chunk);
1153 }
1154 else
1155 {
1156 grub_printf(" [ FAILED ]\n");
1157 }
1158 }
1159 }
1160
1161 return;
1162 }
1163
1164 install_template * ventoy_plugin_find_install_template(const char *isopath)
1165 {
1166 install_template *node = NULL;
1167 int len = (int)grub_strlen(isopath);
1168
1169 for (node = g_install_template_head; node; node = node->next)
1170 {
1171 if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1172 {
1173 return node;
1174 }
1175 }
1176
1177 return NULL;
1178 }
1179
1180 char * ventoy_plugin_get_cur_install_template(const char *isopath)
1181 {
1182 install_template *node = NULL;
1183
1184 node = ventoy_plugin_find_install_template(isopath);
1185 if ((!node) || (!node->templatepath))
1186 {
1187 return NULL;
1188 }
1189
1190 if (node->cursel < 0 || node->cursel >= node->templatenum)
1191 {
1192 return NULL;
1193 }
1194
1195 return node->templatepath[node->cursel].path;
1196 }
1197
1198 persistence_config * ventoy_plugin_find_persistent(const char *isopath)
1199 {
1200 persistence_config *node = NULL;
1201 int len = (int)grub_strlen(isopath);
1202
1203 for (node = g_persistence_head; node; node = node->next)
1204 {
1205 if ((len == node->pathlen) && (grub_strcmp(node->isopath, isopath) == 0))
1206 {
1207 return node;
1208 }
1209 }
1210
1211 return NULL;
1212 }
1213
1214 int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list)
1215 {
1216 int rc = 1;
1217 grub_uint64_t start = 0;
1218 grub_file_t file = NULL;
1219 persistence_config *node = NULL;
1220
1221 node = ventoy_plugin_find_persistent(isopath);
1222 if ((!node) || (!node->backendpath))
1223 {
1224 return 1;
1225 }
1226
1227 if (index < 0)
1228 {
1229 index = node->cursel;
1230 }
1231
1232 if (index < 0 || index >= node->backendnum)
1233 {
1234 return 1;
1235 }
1236
1237 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->backendpath[index].path);
1238 if (!file)
1239 {
1240 debug("Failed to open file %s%s\n", g_iso_disk_name, node->backendpath[index].path);
1241 goto end;
1242 }
1243
1244 grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list));
1245 chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1246 if (NULL == chunk_list->chunk)
1247 {
1248 goto end;
1249 }
1250
1251 chunk_list->max_chunk = DEFAULT_CHUNK_NUM;
1252 chunk_list->cur_chunk = 0;
1253
1254 start = file->device->disk->partition->start;
1255 ventoy_get_block_list(file, chunk_list, start);
1256
1257 if (0 != ventoy_check_block_list(file, chunk_list, start))
1258 {
1259 grub_free(chunk_list->chunk);
1260 chunk_list->chunk = NULL;
1261 goto end;
1262 }
1263
1264 rc = 0;
1265
1266 end:
1267 if (file)
1268 grub_file_close(file);
1269
1270 return rc;
1271 }
1272
1273 const char * ventoy_plugin_get_injection(const char *isopath)
1274 {
1275 injection_config *node = NULL;
1276 int len = (int)grub_strlen(isopath);
1277
1278 for (node = g_injection_head; node; node = node->next)
1279 {
1280 if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1281 {
1282 return node->archive;
1283 }
1284 }
1285
1286 return NULL;
1287 }
1288
1289 const char * ventoy_plugin_get_menu_alias(int type, const char *isopath)
1290 {
1291 menu_alias *node = NULL;
1292 int len = (int)grub_strlen(isopath);
1293
1294 for (node = g_menu_alias_head; node; node = node->next)
1295 {
1296 if (node->type == type && node->pathlen &&
1297 node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1298 {
1299 return node->alias;
1300 }
1301 }
1302
1303 return NULL;
1304 }
1305
1306 const char * ventoy_plugin_get_menu_class(int type, const char *name)
1307 {
1308 menu_class *node = NULL;
1309 int len = (int)grub_strlen(name);
1310
1311 if (vtoy_class_image_file == type)
1312 {
1313 for (node = g_menu_class_head; node; node = node->next)
1314 {
1315 if (node->type == type && node->patlen <= len && grub_strstr(name, node->pattern))
1316 {
1317 return node->class;
1318 }
1319 }
1320 }
1321 else
1322 {
1323 for (node = g_menu_class_head; node; node = node->next)
1324 {
1325 if (node->type == type && node->patlen == len && grub_strncmp(name, node->pattern, len) == 0)
1326 {
1327 return node->class;
1328 }
1329 }
1330 }
1331
1332 return NULL;
1333 }
1334
1335 grub_err_t ventoy_cmd_plugin_check_json(grub_extcmd_context_t ctxt, int argc, char **args)
1336 {
1337 int i = 0;
1338 int ret = 0;
1339 char *buf = NULL;
1340 grub_file_t file;
1341 VTOY_JSON *node = NULL;
1342 VTOY_JSON *json = NULL;
1343
1344 (void)ctxt;
1345
1346 if (argc != 3)
1347 {
1348 return 0;
1349 }
1350
1351 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
1352 if (!file)
1353 {
1354 grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\n");
1355 goto end;
1356 }
1357
1358 buf = grub_malloc(file->size + 1);
1359 if (!buf)
1360 {
1361 grub_printf("Failed to malloc memory %lu.\n", (ulong)(file->size + 1));
1362 goto end;
1363 }
1364
1365 buf[file->size] = 0;
1366 grub_file_read(file, buf, file->size);
1367
1368 json = vtoy_json_create();
1369 if (!json)
1370 {
1371 grub_printf("Failed to create json\n");
1372 goto end;
1373 }
1374
1375 ret = vtoy_json_parse(json, buf);
1376 if (ret)
1377 {
1378 grub_printf("Syntax error detected in ventoy.json, please check it.\n");
1379 goto end;
1380 }
1381
1382 for (node = json->pstChild; node; node = node->pstNext)
1383 {
1384 if (grub_strcmp(node->pcName, args[1]) == 0)
1385 {
1386 break;
1387 }
1388 }
1389
1390 if (!node)
1391 {
1392 grub_printf("%s is NOT found in ventoy.json\n", args[1]);
1393 goto end;
1394 }
1395
1396 for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
1397 {
1398 if (grub_strcmp(g_plugin_entries[i].key, args[1]) == 0)
1399 {
1400 if (g_plugin_entries[i].checkfunc)
1401 {
1402 ret = g_plugin_entries[i].checkfunc(node, args[2]);
1403 }
1404 break;
1405 }
1406 }
1407
1408 end:
1409 check_free(file, grub_file_close);
1410 check_free(json, vtoy_json_destroy);
1411 grub_check_free(buf);
1412
1413 return 0;
1414 }
1415