]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
a0ffde37d2f914d52695daa56f7517fe7173ae37
[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_auto_install(void)
1091 {
1092 int i;
1093 install_template *node = NULL;
1094
1095 for (node = g_install_template_head; node; node = node->next)
1096 {
1097 grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->templatenum);
1098 for (i = 0; i < node->templatenum; i++)
1099 {
1100 grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path);
1101 }
1102 }
1103
1104 return;
1105 }
1106
1107 void ventoy_plugin_dump_persistence(void)
1108 {
1109 int rc;
1110 int i = 0;
1111 persistence_config *node = NULL;
1112 ventoy_img_chunk_list chunk_list;
1113
1114 for (node = g_persistence_head; node; node = node->next)
1115 {
1116 grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->backendnum);
1117
1118 for (i = 0; i < node->backendnum; i++)
1119 {
1120 grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path);
1121 rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list);
1122 if (rc == 0)
1123 {
1124 grub_printf(" [ SUCCESS ]\n");
1125 grub_free(chunk_list.chunk);
1126 }
1127 else
1128 {
1129 grub_printf(" [ FAILED ]\n");
1130 }
1131 }
1132 }
1133
1134 return;
1135 }
1136
1137 install_template * ventoy_plugin_find_install_template(const char *isopath)
1138 {
1139 install_template *node = NULL;
1140 int len = (int)grub_strlen(isopath);
1141
1142 for (node = g_install_template_head; node; node = node->next)
1143 {
1144 if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1145 {
1146 return node;
1147 }
1148 }
1149
1150 return NULL;
1151 }
1152
1153 char * ventoy_plugin_get_cur_install_template(const char *isopath)
1154 {
1155 install_template *node = NULL;
1156
1157 node = ventoy_plugin_find_install_template(isopath);
1158 if ((!node) || (!node->templatepath))
1159 {
1160 return NULL;
1161 }
1162
1163 if (node->cursel < 0 || node->cursel >= node->templatenum)
1164 {
1165 return NULL;
1166 }
1167
1168 return node->templatepath[node->cursel].path;
1169 }
1170
1171 persistence_config * ventoy_plugin_find_persistent(const char *isopath)
1172 {
1173 persistence_config *node = NULL;
1174 int len = (int)grub_strlen(isopath);
1175
1176 for (node = g_persistence_head; node; node = node->next)
1177 {
1178 if ((len == node->pathlen) && (grub_strcmp(node->isopath, isopath) == 0))
1179 {
1180 return node;
1181 }
1182 }
1183
1184 return NULL;
1185 }
1186
1187 int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list)
1188 {
1189 int rc = 1;
1190 grub_uint64_t start = 0;
1191 grub_file_t file = NULL;
1192 persistence_config *node = NULL;
1193
1194 node = ventoy_plugin_find_persistent(isopath);
1195 if ((!node) || (!node->backendpath))
1196 {
1197 return 1;
1198 }
1199
1200 if (index < 0)
1201 {
1202 index = node->cursel;
1203 }
1204
1205 if (index < 0 || index >= node->backendnum)
1206 {
1207 return 1;
1208 }
1209
1210 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->backendpath[index].path);
1211 if (!file)
1212 {
1213 debug("Failed to open file %s%s\n", g_iso_disk_name, node->backendpath[index].path);
1214 goto end;
1215 }
1216
1217 grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list));
1218 chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
1219 if (NULL == chunk_list->chunk)
1220 {
1221 goto end;
1222 }
1223
1224 chunk_list->max_chunk = DEFAULT_CHUNK_NUM;
1225 chunk_list->cur_chunk = 0;
1226
1227 start = file->device->disk->partition->start;
1228 ventoy_get_block_list(file, chunk_list, start);
1229
1230 if (0 != ventoy_check_block_list(file, chunk_list, start))
1231 {
1232 grub_free(chunk_list->chunk);
1233 chunk_list->chunk = NULL;
1234 goto end;
1235 }
1236
1237 rc = 0;
1238
1239 end:
1240 if (file)
1241 grub_file_close(file);
1242
1243 return rc;
1244 }
1245
1246 const char * ventoy_plugin_get_injection(const char *isopath)
1247 {
1248 injection_config *node = NULL;
1249 int len = (int)grub_strlen(isopath);
1250
1251 for (node = g_injection_head; node; node = node->next)
1252 {
1253 if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1254 {
1255 return node->archive;
1256 }
1257 }
1258
1259 return NULL;
1260 }
1261
1262 const char * ventoy_plugin_get_menu_alias(int type, const char *isopath)
1263 {
1264 menu_alias *node = NULL;
1265 int len = (int)grub_strlen(isopath);
1266
1267 for (node = g_menu_alias_head; node; node = node->next)
1268 {
1269 if (node->type == type && node->pathlen &&
1270 node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
1271 {
1272 return node->alias;
1273 }
1274 }
1275
1276 return NULL;
1277 }
1278
1279 const char * ventoy_plugin_get_menu_class(int type, const char *name)
1280 {
1281 menu_class *node = NULL;
1282 int len = (int)grub_strlen(name);
1283
1284 if (vtoy_class_image_file == type)
1285 {
1286 for (node = g_menu_class_head; node; node = node->next)
1287 {
1288 if (node->type == type && node->patlen <= len && grub_strstr(name, node->pattern))
1289 {
1290 return node->class;
1291 }
1292 }
1293 }
1294 else
1295 {
1296 for (node = g_menu_class_head; node; node = node->next)
1297 {
1298 if (node->type == type && node->patlen == len && grub_strncmp(name, node->pattern, len) == 0)
1299 {
1300 return node->class;
1301 }
1302 }
1303 }
1304
1305 return NULL;
1306 }
1307
1308 grub_err_t ventoy_cmd_plugin_check_json(grub_extcmd_context_t ctxt, int argc, char **args)
1309 {
1310 int i = 0;
1311 int ret = 0;
1312 char *buf = NULL;
1313 grub_file_t file;
1314 VTOY_JSON *node = NULL;
1315 VTOY_JSON *json = NULL;
1316
1317 (void)ctxt;
1318
1319 if (argc != 3)
1320 {
1321 return 0;
1322 }
1323
1324 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
1325 if (!file)
1326 {
1327 grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\n");
1328 goto end;
1329 }
1330
1331 buf = grub_malloc(file->size + 1);
1332 if (!buf)
1333 {
1334 grub_printf("Failed to malloc memory %lu.\n", (ulong)(file->size + 1));
1335 goto end;
1336 }
1337
1338 buf[file->size] = 0;
1339 grub_file_read(file, buf, file->size);
1340
1341 json = vtoy_json_create();
1342 if (!json)
1343 {
1344 grub_printf("Failed to create json\n");
1345 goto end;
1346 }
1347
1348 ret = vtoy_json_parse(json, buf);
1349 if (ret)
1350 {
1351 grub_printf("Syntax error detected in ventoy.json, please check it.\n");
1352 goto end;
1353 }
1354
1355 for (node = json->pstChild; node; node = node->pstNext)
1356 {
1357 if (grub_strcmp(node->pcName, args[1]) == 0)
1358 {
1359 break;
1360 }
1361 }
1362
1363 if (!node)
1364 {
1365 grub_printf("%s is NOT found in ventoy.json\n", args[1]);
1366 goto end;
1367 }
1368
1369 for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
1370 {
1371 if (grub_strcmp(g_plugin_entries[i].key, args[1]) == 0)
1372 {
1373 if (g_plugin_entries[i].checkfunc)
1374 {
1375 ret = g_plugin_entries[i].checkfunc(node, args[2]);
1376 }
1377 break;
1378 }
1379 }
1380
1381 end:
1382 check_free(file, grub_file_close);
1383 check_free(json, vtoy_json_destroy);
1384 grub_check_free(buf);
1385
1386 return 0;
1387 }
1388