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