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