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