]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
4aad58d81adbad7a8ef76c9ec6bedf3ffa475612
[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/ventoy.h>
37 #include "ventoy_def.h"
38
39 GRUB_MOD_LICENSE ("GPLv3+");
40
41 static char g_iso_disk_name[128];
42 static install_template *g_install_template_head = NULL;
43 static persistence_config *g_persistence_head = NULL;
44
45 static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
46 {
47 VTOY_JSON *pNode = NULL;
48 VTOY_JSON *pChild = NULL;
49
50 (void)isodisk;
51
52 if (json->enDataType != JSON_TYPE_ARRAY)
53 {
54 debug("Not array %d\n", json->enDataType);
55 return 0;
56 }
57
58 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
59 {
60 if (pNode->enDataType == JSON_TYPE_OBJECT)
61 {
62 pChild = pNode->pstChild;
63 if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal)
64 {
65 ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal);
66 }
67 }
68 }
69
70 return 0;
71 }
72
73 static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
74 {
75 const char *value;
76 char filepath[256];
77
78 value = vtoy_json_get_string_ex(json->pstChild, "file");
79 if (value)
80 {
81 if (value[0] == '/')
82 {
83 grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value);
84 }
85 else
86 {
87 grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value);
88 }
89
90 if (ventoy_is_file_exist(filepath) == 0)
91 {
92 debug("Theme file %s does not exist\n", filepath);
93 return 0;
94 }
95
96 debug("vtoy_theme %s\n", filepath);
97 grub_env_set("vtoy_theme", filepath);
98 }
99
100 value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
101 if (value)
102 {
103 debug("vtoy_gfxmode %s\n", value);
104 grub_env_set("vtoy_gfxmode", value);
105 }
106
107 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
108 if (value)
109 {
110 grub_env_set("VTLE_LFT", value);
111 }
112
113 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top");
114 if (value)
115 {
116 grub_env_set("VTLE_TOP", value);
117 }
118
119 value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color");
120 if (value)
121 {
122 grub_env_set("VTLE_CLR", value);
123 }
124
125 return 0;
126 }
127
128 static int ventoy_plugin_parse_fullpath
129 (
130 VTOY_JSON *json,
131 const char *isodisk,
132 const char *key,
133 file_fullpath **fullpath,
134 int *pathnum
135 )
136 {
137 int rc = 1;
138 int count = 0;
139 VTOY_JSON *node = json;
140 VTOY_JSON *child = NULL;
141 file_fullpath *path = NULL;
142
143 while (node)
144 {
145 if (0 == grub_strcmp(key, node->pcName))
146 {
147 break;
148 }
149 node = node->pstNext;
150 }
151
152 if (!node)
153 {
154 return 1;
155 }
156
157 if (JSON_TYPE_STRING == node->enDataType)
158 {
159 debug("%s is string type data\n", node->pcName);
160
161 if ((node->unData.pcStrVal[0] != '/') || (!ventoy_is_file_exist("%s%s", isodisk, node->unData.pcStrVal)))
162 {
163 debug("%s%s file not found\n", isodisk, node->unData.pcStrVal);
164 return 1;
165 }
166
167 path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath));
168 if (path)
169 {
170 grub_snprintf(path->path, sizeof(path->path), "%s", node->unData.pcStrVal);
171 *fullpath = path;
172 *pathnum = 1;
173 rc = 0;
174 }
175 }
176 else if (JSON_TYPE_ARRAY == node->enDataType)
177 {
178 for (child = node->pstChild; child; child = child->pstNext)
179 {
180 if ((JSON_TYPE_STRING != child->enDataType) || (child->unData.pcStrVal[0] != '/'))
181 {
182 debug("Invalid data type:%d\n", child->enDataType);
183 return 1;
184 }
185 count++;
186 }
187 debug("%s is array type data, count=%d\n", node->pcName, count);
188
189 path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath) * count);
190 if (path)
191 {
192 *fullpath = path;
193
194 for (count = 0, child = node->pstChild; child; child = child->pstNext)
195 {
196 if (ventoy_is_file_exist("%s%s", isodisk, child->unData.pcStrVal))
197 {
198 grub_snprintf(path->path, sizeof(path->path), "%s", child->unData.pcStrVal);
199 path++;
200 count++;
201 }
202 }
203
204 *pathnum = count;
205 rc = 0;
206 }
207 }
208
209 return rc;
210 }
211
212 static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk)
213 {
214 int pathnum = 0;
215 const char *iso = NULL;
216 VTOY_JSON *pNode = NULL;
217 install_template *node = NULL;
218 install_template *next = NULL;
219 file_fullpath *templatepath = NULL;
220
221 if (json->enDataType != JSON_TYPE_ARRAY)
222 {
223 debug("Not array %d\n", json->enDataType);
224 return 0;
225 }
226
227 if (g_install_template_head)
228 {
229 for (node = g_install_template_head; node; node = next)
230 {
231 next = node->next;
232 grub_check_free(node->templatepath);
233 grub_free(node);
234 }
235
236 g_install_template_head = NULL;
237 }
238
239 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
240 {
241 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
242 if (iso && iso[0] == '/')
243 {
244 if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "template", &templatepath, &pathnum))
245 {
246 node = grub_zalloc(sizeof(install_template));
247 if (node)
248 {
249 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
250 node->templatepath = templatepath;
251 node->templatenum = pathnum;
252
253 if (g_install_template_head)
254 {
255 node->next = g_install_template_head;
256 }
257
258 g_install_template_head = node;
259 }
260 }
261 }
262 }
263
264 return 0;
265 }
266
267
268 static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk)
269 {
270 int pathnum = 0;
271 const char *iso = NULL;
272 VTOY_JSON *pNode = NULL;
273 persistence_config *node = NULL;
274 persistence_config *next = NULL;
275 file_fullpath *backendpath = NULL;
276
277 (void)isodisk;
278
279 if (json->enDataType != JSON_TYPE_ARRAY)
280 {
281 debug("Not array %d\n", json->enDataType);
282 return 0;
283 }
284
285 if (g_persistence_head)
286 {
287 for (node = g_persistence_head; node; node = next)
288 {
289 next = node->next;
290 grub_check_free(node->backendpath);
291 grub_free(node);
292 }
293
294 g_persistence_head = NULL;
295 }
296
297 for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
298 {
299 iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
300 if (iso && iso[0] == '/')
301 {
302 if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "backend", &backendpath, &pathnum))
303 {
304 node = grub_zalloc(sizeof(persistence_config));
305 if (node)
306 {
307 node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
308 node->backendpath = backendpath;
309 node->backendnum = pathnum;
310
311 if (g_persistence_head)
312 {
313 node->next = g_persistence_head;
314 }
315
316 g_persistence_head = node;
317 }
318 }
319 }
320 }
321
322 return 0;
323 }
324
325
326 static plugin_entry g_plugin_entries[] =
327 {
328 { "control", ventoy_plugin_control_entry },
329 { "theme", ventoy_plugin_theme_entry },
330 { "auto_install", ventoy_plugin_auto_install_entry },
331 { "persistence", ventoy_plugin_persistence_entry },
332 };
333
334 static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
335 {
336 int i;
337 VTOY_JSON *cur = json;
338
339 grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk);
340
341 while (cur)
342 {
343 for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
344 {
345 if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0)
346 {
347 debug("Plugin entry for %s\n", g_plugin_entries[i].key);
348 g_plugin_entries[i].entryfunc(cur, isodisk);
349 break;
350 }
351 }
352
353 cur = cur->pstNext;
354 }
355
356 return 0;
357 }
358
359 grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args)
360 {
361 int ret = 0;
362 char *buf = NULL;
363 grub_file_t file;
364 VTOY_JSON *json = NULL;
365
366 (void)ctxt;
367 (void)argc;
368
369 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
370 if (!file)
371 {
372 return GRUB_ERR_NONE;
373 }
374
375 debug("json configuration file size %d\n", (int)file->size);
376
377 buf = grub_malloc(file->size + 1);
378 if (!buf)
379 {
380 grub_file_close(file);
381 return 1;
382 }
383
384 buf[file->size] = 0;
385 grub_file_read(file, buf, file->size);
386 grub_file_close(file);
387
388 json = vtoy_json_create();
389 if (!json)
390 {
391 return 1;
392 }
393
394
395
396 ret = vtoy_json_parse(json, buf);
397 if (ret)
398 {
399 debug("Failed to parse json string %d\n", ret);
400 grub_free(buf);
401 return 1;
402 }
403
404 ventoy_parse_plugin_config(json->pstChild, args[0]);
405
406 vtoy_json_destroy(json);
407
408 grub_free(buf);
409
410 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
411 }
412
413 void ventoy_plugin_dump_auto_install(void)
414 {
415 int i;
416 install_template *node = NULL;
417
418 for (node = g_install_template_head; node; node = node->next)
419 {
420 grub_printf("\nIMAGE:<%s>\n", node->isopath);
421 for (i = 0; i < node->templatenum; i++)
422 {
423 grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path);
424 }
425 }
426
427 return;
428 }
429
430 void ventoy_plugin_dump_persistence(void)
431 {
432 int rc;
433 int i = 0;
434 persistence_config *node = NULL;
435 ventoy_img_chunk_list chunk_list;
436
437 for (node = g_persistence_head; node; node = node->next)
438 {
439 grub_printf("\nIMAGE:<%s>\n", node->isopath);
440
441 for (i = 0; i < node->backendnum; i++)
442 {
443 grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path);
444 rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list);
445 if (rc == 0)
446 {
447 grub_printf(" [ SUCCESS ]\n");
448 grub_free(chunk_list.chunk);
449 }
450 else
451 {
452 grub_printf(" [ FAILED ]\n");
453 }
454 }
455 }
456
457 return;
458 }
459
460 install_template * ventoy_plugin_find_install_template(const char *isopath)
461 {
462 install_template *node = NULL;
463 int len = (int)grub_strlen(isopath);
464
465 for (node = g_install_template_head; node; node = node->next)
466 {
467 if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
468 {
469 return node;
470 }
471 }
472
473 return NULL;
474 }
475
476 char * ventoy_plugin_get_cur_install_template(const char *isopath)
477 {
478 install_template *node = NULL;
479
480 node = ventoy_plugin_find_install_template(isopath);
481 if ((!node) || (!node->templatepath))
482 {
483 return NULL;
484 }
485
486 if (node->cursel < 0 || node->cursel >= node->templatenum)
487 {
488 return NULL;
489 }
490
491 return node->templatepath[node->cursel].path;
492 }
493
494 persistence_config * ventoy_plugin_find_persistent(const char *isopath)
495 {
496 persistence_config *node = NULL;
497 int len = (int)grub_strlen(isopath);
498
499 for (node = g_persistence_head; node; node = node->next)
500 {
501 if ((len == node->pathlen) && (grub_strcmp(node->isopath, isopath) == 0))
502 {
503 return node;
504 }
505 }
506
507 return NULL;
508 }
509
510 int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list)
511 {
512 int rc = 1;
513 grub_uint64_t start = 0;
514 grub_file_t file = NULL;
515 persistence_config *node = NULL;
516
517 node = ventoy_plugin_find_persistent(isopath);
518 if ((!node) || (!node->backendpath))
519 {
520 return 1;
521 }
522
523 if (index < 0)
524 {
525 index = node->cursel;
526 }
527
528 if (index < 0 || index >= node->backendnum)
529 {
530 return 1;
531 }
532
533 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->backendpath[index].path);
534 if (!file)
535 {
536 debug("Failed to open file %s%s\n", g_iso_disk_name, node->backendpath[index].path);
537 goto end;
538 }
539
540 grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list));
541 chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
542 if (NULL == chunk_list->chunk)
543 {
544 goto end;
545 }
546
547 chunk_list->max_chunk = DEFAULT_CHUNK_NUM;
548 chunk_list->cur_chunk = 0;
549
550 start = file->device->disk->partition->start;
551 ventoy_get_block_list(file, chunk_list, start);
552
553 if (0 != ventoy_check_block_list(file, chunk_list, start))
554 {
555 grub_free(chunk_list->chunk);
556 chunk_list->chunk = NULL;
557 goto end;
558 }
559
560 rc = 0;
561
562 end:
563 if (file)
564 grub_file_close(file);
565
566 return rc;
567 }
568