1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
20 #include <grub/types.h>
21 #include <grub/misc.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>
35 #include <grub/time.h>
36 #include <grub/ventoy.h>
37 #include "ventoy_def.h"
39 GRUB_MOD_LICENSE ("GPLv3+");
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
;
45 static int ventoy_plugin_control_entry(VTOY_JSON
*json
, const char *isodisk
)
47 VTOY_JSON
*pNode
= NULL
;
48 VTOY_JSON
*pChild
= NULL
;
52 if (json
->enDataType
!= JSON_TYPE_ARRAY
)
54 debug("Not array %d\n", json
->enDataType
);
58 for (pNode
= json
->pstChild
; pNode
; pNode
= pNode
->pstNext
)
60 if (pNode
->enDataType
== JSON_TYPE_OBJECT
)
62 pChild
= pNode
->pstChild
;
63 if (pChild
->enDataType
== JSON_TYPE_STRING
&& pChild
->pcName
&& pChild
->unData
.pcStrVal
)
65 ventoy_set_env(pChild
->pcName
, pChild
->unData
.pcStrVal
);
73 static int ventoy_plugin_theme_entry(VTOY_JSON
*json
, const char *isodisk
)
78 value
= vtoy_json_get_string_ex(json
->pstChild
, "file");
83 grub_snprintf(filepath
, sizeof(filepath
), "%s%s", isodisk
, value
);
87 grub_snprintf(filepath
, sizeof(filepath
), "%s/ventoy/%s", isodisk
, value
);
90 if (ventoy_is_file_exist(filepath
) == 0)
92 debug("Theme file %s does not exist\n", filepath
);
96 debug("vtoy_theme %s\n", filepath
);
97 grub_env_set("vtoy_theme", filepath
);
100 value
= vtoy_json_get_string_ex(json
->pstChild
, "gfxmode");
103 debug("vtoy_gfxmode %s\n", value
);
104 grub_env_set("vtoy_gfxmode", value
);
107 value
= vtoy_json_get_string_ex(json
->pstChild
, "ventoy_left");
110 grub_env_set("VTLE_LFT", value
);
113 value
= vtoy_json_get_string_ex(json
->pstChild
, "ventoy_top");
116 grub_env_set("VTLE_TOP", value
);
119 value
= vtoy_json_get_string_ex(json
->pstChild
, "ventoy_color");
122 grub_env_set("VTLE_CLR", value
);
128 static int ventoy_plugin_parse_fullpath
133 file_fullpath
**fullpath
,
139 VTOY_JSON
*node
= json
;
140 VTOY_JSON
*child
= NULL
;
141 file_fullpath
*path
= NULL
;
145 if (0 == grub_strcmp(key
, node
->pcName
))
149 node
= node
->pstNext
;
157 if (JSON_TYPE_STRING
== node
->enDataType
)
159 debug("%s is string type data\n", node
->pcName
);
161 if ((node
->unData
.pcStrVal
[0] != '/') || (!ventoy_is_file_exist("%s%s", isodisk
, node
->unData
.pcStrVal
)))
163 debug("%s%s file not found\n", isodisk
, node
->unData
.pcStrVal
);
167 path
= (file_fullpath
*)grub_zalloc(sizeof(file_fullpath
));
170 grub_snprintf(path
->path
, sizeof(path
->path
), "%s", node
->unData
.pcStrVal
);
176 else if (JSON_TYPE_ARRAY
== node
->enDataType
)
178 for (child
= node
->pstChild
; child
; child
= child
->pstNext
)
180 if ((JSON_TYPE_STRING
!= child
->enDataType
) || (child
->unData
.pcStrVal
[0] != '/'))
182 debug("Invalid data type:%d\n", child
->enDataType
);
187 debug("%s is array type data, count=%d\n", node
->pcName
, count
);
189 path
= (file_fullpath
*)grub_zalloc(sizeof(file_fullpath
) * count
);
194 for (count
= 0, child
= node
->pstChild
; child
; child
= child
->pstNext
)
196 if (ventoy_is_file_exist("%s%s", isodisk
, child
->unData
.pcStrVal
))
198 grub_snprintf(path
->path
, sizeof(path
->path
), "%s", child
->unData
.pcStrVal
);
212 static int ventoy_plugin_auto_install_entry(VTOY_JSON
*json
, const char *isodisk
)
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
;
221 if (json
->enDataType
!= JSON_TYPE_ARRAY
)
223 debug("Not array %d\n", json
->enDataType
);
227 if (g_install_template_head
)
229 for (node
= g_install_template_head
; node
; node
= next
)
232 grub_check_free(node
->templatepath
);
236 g_install_template_head
= NULL
;
239 for (pNode
= json
->pstChild
; pNode
; pNode
= pNode
->pstNext
)
241 iso
= vtoy_json_get_string_ex(pNode
->pstChild
, "image");
242 if (iso
&& iso
[0] == '/')
244 if (0 == ventoy_plugin_parse_fullpath(pNode
->pstChild
, isodisk
, "template", &templatepath
, &pathnum
))
246 node
= grub_zalloc(sizeof(install_template
));
249 node
->pathlen
= grub_snprintf(node
->isopath
, sizeof(node
->isopath
), "%s", iso
);
250 node
->templatepath
= templatepath
;
251 node
->templatenum
= pathnum
;
253 if (g_install_template_head
)
255 node
->next
= g_install_template_head
;
258 g_install_template_head
= node
;
268 static int ventoy_plugin_persistence_entry(VTOY_JSON
*json
, const char *isodisk
)
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
;
279 if (json
->enDataType
!= JSON_TYPE_ARRAY
)
281 debug("Not array %d\n", json
->enDataType
);
285 if (g_persistence_head
)
287 for (node
= g_persistence_head
; node
; node
= next
)
290 grub_check_free(node
->backendpath
);
294 g_persistence_head
= NULL
;
297 for (pNode
= json
->pstChild
; pNode
; pNode
= pNode
->pstNext
)
299 iso
= vtoy_json_get_string_ex(pNode
->pstChild
, "image");
300 if (iso
&& iso
[0] == '/')
302 if (0 == ventoy_plugin_parse_fullpath(pNode
->pstChild
, isodisk
, "backend", &backendpath
, &pathnum
))
304 node
= grub_zalloc(sizeof(persistence_config
));
307 node
->pathlen
= grub_snprintf(node
->isopath
, sizeof(node
->isopath
), "%s", iso
);
308 node
->backendpath
= backendpath
;
309 node
->backendnum
= pathnum
;
311 if (g_persistence_head
)
313 node
->next
= g_persistence_head
;
316 g_persistence_head
= node
;
326 static plugin_entry g_plugin_entries
[] =
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
},
334 static int ventoy_parse_plugin_config(VTOY_JSON
*json
, const char *isodisk
)
337 VTOY_JSON
*cur
= json
;
339 grub_snprintf(g_iso_disk_name
, sizeof(g_iso_disk_name
), "%s", isodisk
);
343 for (i
= 0; i
< (int)ARRAY_SIZE(g_plugin_entries
); i
++)
345 if (grub_strcmp(g_plugin_entries
[i
].key
, cur
->pcName
) == 0)
347 debug("Plugin entry for %s\n", g_plugin_entries
[i
].key
);
348 g_plugin_entries
[i
].entryfunc(cur
, isodisk
);
359 grub_err_t
ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
364 VTOY_JSON
*json
= NULL
;
369 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/ventoy/ventoy.json", args
[0]);
372 return GRUB_ERR_NONE
;
375 debug("json configuration file size %d\n", (int)file
->size
);
377 buf
= grub_malloc(file
->size
+ 1);
380 grub_file_close(file
);
385 grub_file_read(file
, buf
, file
->size
);
386 grub_file_close(file
);
388 json
= vtoy_json_create();
396 ret
= vtoy_json_parse(json
, buf
);
399 debug("Failed to parse json string %d\n", ret
);
404 ventoy_parse_plugin_config(json
->pstChild
, args
[0]);
406 vtoy_json_destroy(json
);
410 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
413 void ventoy_plugin_dump_auto_install(void)
416 install_template
*node
= NULL
;
418 for (node
= g_install_template_head
; node
; node
= node
->next
)
420 grub_printf("\nIMAGE:<%s>\n", node
->isopath
);
421 for (i
= 0; i
< node
->templatenum
; i
++)
423 grub_printf("SCRIPT %d:<%s>\n", i
, node
->templatepath
[i
].path
);
430 void ventoy_plugin_dump_persistence(void)
434 persistence_config
*node
= NULL
;
435 ventoy_img_chunk_list chunk_list
;
437 for (node
= g_persistence_head
; node
; node
= node
->next
)
439 grub_printf("\nIMAGE:<%s>\n", node
->isopath
);
441 for (i
= 0; i
< node
->backendnum
; i
++)
443 grub_printf("PERSIST %d:<%s>", i
, node
->backendpath
[i
].path
);
444 rc
= ventoy_plugin_get_persistent_chunklist(node
->isopath
, i
, &chunk_list
);
447 grub_printf(" [ SUCCESS ]\n");
448 grub_free(chunk_list
.chunk
);
452 grub_printf(" [ FAILED ]\n");
460 install_template
* ventoy_plugin_find_install_template(const char *isopath
)
462 install_template
*node
= NULL
;
463 int len
= (int)grub_strlen(isopath
);
465 for (node
= g_install_template_head
; node
; node
= node
->next
)
467 if (node
->pathlen
== len
&& grub_strcmp(node
->isopath
, isopath
) == 0)
476 char * ventoy_plugin_get_cur_install_template(const char *isopath
)
478 install_template
*node
= NULL
;
480 node
= ventoy_plugin_find_install_template(isopath
);
481 if ((!node
) || (!node
->templatepath
))
486 if (node
->cursel
< 0 || node
->cursel
>= node
->templatenum
)
491 return node
->templatepath
[node
->cursel
].path
;
494 persistence_config
* ventoy_plugin_find_persistent(const char *isopath
)
496 persistence_config
*node
= NULL
;
497 int len
= (int)grub_strlen(isopath
);
499 for (node
= g_persistence_head
; node
; node
= node
->next
)
501 if ((len
== node
->pathlen
) && (grub_strcmp(node
->isopath
, isopath
) == 0))
510 int ventoy_plugin_get_persistent_chunklist(const char *isopath
, int index
, ventoy_img_chunk_list
*chunk_list
)
513 grub_uint64_t start
= 0;
514 grub_file_t file
= NULL
;
515 persistence_config
*node
= NULL
;
517 node
= ventoy_plugin_find_persistent(isopath
);
518 if ((!node
) || (!node
->backendpath
))
525 index
= node
->cursel
;
528 if (index
< 0 || index
>= node
->backendnum
)
533 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", g_iso_disk_name
, node
->backendpath
[index
].path
);
536 debug("Failed to open file %s%s\n", g_iso_disk_name
, node
->backendpath
[index
].path
);
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
)
547 chunk_list
->max_chunk
= DEFAULT_CHUNK_NUM
;
548 chunk_list
->cur_chunk
= 0;
550 start
= file
->device
->disk
->partition
->start
;
551 ventoy_get_block_list(file
, chunk_list
, start
);
553 if (0 != ventoy_check_block_list(file
, chunk_list
, start
))
555 grub_free(chunk_list
->chunk
);
556 chunk_list
->chunk
= NULL
;
564 grub_file_close(file
);