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