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