/****************************************************************************** * ventoy_plugin.c * * Copyright (c) 2020, longpanda * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ventoy_def.h" GRUB_MOD_LICENSE ("GPLv3+"); char g_arch_mode_suffix[64]; static char g_iso_disk_name[128]; static grub_uint8_t g_boot_pwd = 0; static grub_uint8_t g_boot_sha256[32]; static install_template *g_install_template_head = NULL; static dud *g_dud_head = NULL; static vtoy_password *g_pwd_head = NULL; static persistence_config *g_persistence_head = NULL; static menu_alias *g_menu_alias_head = NULL; static menu_class *g_menu_class_head = NULL; static injection_config *g_injection_head = NULL; static auto_memdisk *g_auto_memdisk_head = NULL; static image_list *g_image_list_head = NULL; static conf_replace *g_conf_replace_head = NULL; static int ventoy_plugin_control_check(VTOY_JSON *json, const char *isodisk) { int rc = 0; VTOY_JSON *pNode = NULL; VTOY_JSON *pChild = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array type %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_OBJECT) { pChild = pNode->pstChild; if (pChild->enDataType == JSON_TYPE_STRING) { if (grub_strcmp(pChild->pcName, "VTOY_DEFAULT_IMAGE") == 0) { grub_printf("%s: %s [%s]\n", pChild->pcName, pChild->unData.pcStrVal, ventoy_check_file_exist("%s%s", isodisk, pChild->unData.pcStrVal) ? "OK" : "NOT EXIST"); } else { grub_printf("%s: %s\n", pChild->pcName, pChild->unData.pcStrVal); } } else { grub_printf("%s is NOT string type\n", pChild->pcName); rc = 1; } } else { grub_printf("%s is not an object\n", pNode->pcName); rc = 1; } } return rc; } static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk) { VTOY_JSON *pNode = NULL; VTOY_JSON *pChild = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_OBJECT) { pChild = pNode->pstChild; if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal) { ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal); } } } return 0; } static int ventoy_plugin_theme_check(VTOY_JSON *json, const char *isodisk) { int exist = 0; const char *value; VTOY_JSON *node; value = vtoy_json_get_string_ex(json->pstChild, "file"); if (value) { grub_printf("file: %s\n", value); if (value[0] == '/') { exist = ventoy_is_file_exist("%s%s", isodisk, value); } else { exist = ventoy_is_file_exist("%s/ventoy/%s", isodisk, value); } if (exist == 0) { grub_printf("Theme file %s does NOT exist\n", value); return 1; } } value = vtoy_json_get_string_ex(json->pstChild, "gfxmode"); if (value) { grub_printf("gfxmode: %s\n", value); } value = vtoy_json_get_string_ex(json->pstChild, "display_mode"); if (value) { grub_printf("display_mode: %s\n", value); } value = vtoy_json_get_string_ex(json->pstChild, "serial_param"); if (value) { grub_printf("serial_param %s\n", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left"); if (value) { grub_printf("ventoy_left: %s\n", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top"); if (value) { grub_printf("ventoy_top: %s\n", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color"); if (value) { grub_printf("ventoy_color: %s\n", value); } node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts"); if (node) { for (node = node->pstChild; node; node = node->pstNext) { if (node->enDataType == JSON_TYPE_STRING) { if (ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal)) { grub_printf("%s [OK]\n", node->unData.pcStrVal); } else { grub_printf("%s [NOT EXIST]\n", node->unData.pcStrVal); } } } } else { grub_printf("fonts NOT found\n"); } return 0; } static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk) { const char *value; char filepath[256]; VTOY_JSON *node; value = vtoy_json_get_string_ex(json->pstChild, "file"); if (value) { if (value[0] == '/') { grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value); } else { grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value); } if (ventoy_is_file_exist(filepath) == 0) { debug("Theme file %s does not exist\n", filepath); return 0; } debug("vtoy_theme %s\n", filepath); grub_env_set("vtoy_theme", filepath); } value = vtoy_json_get_string_ex(json->pstChild, "gfxmode"); if (value) { debug("vtoy_gfxmode %s\n", value); grub_env_set("vtoy_gfxmode", value); } value = vtoy_json_get_string_ex(json->pstChild, "display_mode"); if (value) { debug("display_mode %s\n", value); grub_env_set("vtoy_display_mode", value); } value = vtoy_json_get_string_ex(json->pstChild, "serial_param"); if (value) { debug("serial_param %s\n", value); grub_env_set("vtoy_serial_param", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left"); if (value) { grub_env_set("VTLE_LFT", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top"); if (value) { grub_env_set("VTLE_TOP", value); } value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color"); if (value) { grub_env_set("VTLE_CLR", value); } node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts"); if (node) { for (node = node->pstChild; node; node = node->pstNext) { if (node->enDataType == JSON_TYPE_STRING && ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal)) { grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, node->unData.pcStrVal); grub_font_load(filepath); } } } return 0; } static int ventoy_plugin_check_path(const char *path, const char *file) { if (file[0] != '/') { grub_printf("%s is NOT begin with '/' \n", file); return 1; } if (grub_strchr(file, '\\')) { grub_printf("%s contains invalid '\\' \n", file); return 1; } if (grub_strstr(file, "//")) { grub_printf("%s contains invalid double slash\n", file); return 1; } if (grub_strstr(file, "../")) { grub_printf("%s contains invalid '../' \n", file); return 1; } if (!ventoy_is_file_exist("%s%s", path, file)) { grub_printf("%s%s does NOT exist\n", path, file); return 1; } return 0; } static int ventoy_plugin_check_fullpath ( VTOY_JSON *json, const char *isodisk, const char *key, int *pathnum ) { int rc = 0; int ret = 0; int cnt = 0; VTOY_JSON *node = json; VTOY_JSON *child = NULL; while (node) { if (0 == grub_strcmp(key, node->pcName)) { break; } node = node->pstNext; } if (!node) { return 1; } if (JSON_TYPE_STRING == node->enDataType) { cnt = 1; ret = ventoy_plugin_check_path(isodisk, node->unData.pcStrVal); grub_printf("%s: %s [%s]\n", key, node->unData.pcStrVal, ret ? "FAIL" : "OK"); } else if (JSON_TYPE_ARRAY == node->enDataType) { for (child = node->pstChild; child; child = child->pstNext) { if (JSON_TYPE_STRING != child->enDataType) { grub_printf("Non string json type\n"); } else { rc = ventoy_plugin_check_path(isodisk, child->unData.pcStrVal); grub_printf("%s: %s [%s]\n", key, child->unData.pcStrVal, rc ? "FAIL" : "OK"); ret += rc; cnt++; } } } *pathnum = cnt; return ret; } static int ventoy_plugin_parse_fullpath ( VTOY_JSON *json, const char *isodisk, const char *key, file_fullpath **fullpath, int *pathnum ) { int rc = 1; int count = 0; VTOY_JSON *node = json; VTOY_JSON *child = NULL; file_fullpath *path = NULL; while (node) { if (0 == grub_strcmp(key, node->pcName)) { break; } node = node->pstNext; } if (!node) { return 1; } if (JSON_TYPE_STRING == node->enDataType) { debug("%s is string type data\n", node->pcName); if ((node->unData.pcStrVal[0] != '/') || (!ventoy_is_file_exist("%s%s", isodisk, node->unData.pcStrVal))) { debug("%s%s file not found\n", isodisk, node->unData.pcStrVal); return 1; } path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath)); if (path) { grub_snprintf(path->path, sizeof(path->path), "%s", node->unData.pcStrVal); *fullpath = path; *pathnum = 1; rc = 0; } } else if (JSON_TYPE_ARRAY == node->enDataType) { for (child = node->pstChild; child; child = child->pstNext) { if ((JSON_TYPE_STRING != child->enDataType) || (child->unData.pcStrVal[0] != '/')) { debug("Invalid data type:%d\n", child->enDataType); return 1; } count++; } debug("%s is array type data, count=%d\n", node->pcName, count); path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath) * count); if (path) { *fullpath = path; for (count = 0, child = node->pstChild; child; child = child->pstNext) { if (ventoy_is_file_exist("%s%s", isodisk, child->unData.pcStrVal)) { grub_snprintf(path->path, sizeof(path->path), "%s", child->unData.pcStrVal); path++; count++; } } *pathnum = count; rc = 0; } } return rc; } static int ventoy_plugin_auto_install_check(VTOY_JSON *json, const char *isodisk) { int pathnum = 0; int autosel = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array type %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType != JSON_TYPE_OBJECT) { grub_printf("NOT object type\n"); } iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso) { if (0 == ventoy_plugin_check_path(isodisk, iso)) { grub_printf("image: %s [OK]\n", iso); ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "template", &pathnum); if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) { if (autosel >= 0 && autosel <= pathnum) { grub_printf("autosel: %d [OK]\n", autosel); } else { grub_printf("autosel: %d [FAIL]\n", autosel); } } } else { grub_printf("image: %s [FAIL]\n", iso); } } else { grub_printf("image not found\n"); } } return 0; } static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk) { int pathnum = 0; int autosel = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; install_template *node = NULL; install_template *next = NULL; file_fullpath *templatepath = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_install_template_head) { for (node = g_install_template_head; node; node = next) { next = node->next; grub_check_free(node->templatepath); grub_free(node); } g_install_template_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso && iso[0] == '/') { if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "template", &templatepath, &pathnum)) { node = grub_zalloc(sizeof(install_template)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); node->templatepath = templatepath; node->templatenum = pathnum; node->autosel = -1; if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) { if (autosel >= 0 && autosel <= pathnum) { node->autosel = autosel; } } if (g_install_template_head) { node->next = g_install_template_head; } g_install_template_head = node; } } } } return 0; } static int ventoy_plugin_dud_check(VTOY_JSON *json, const char *isodisk) { int pathnum = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array type %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType != JSON_TYPE_OBJECT) { grub_printf("NOT object type\n"); } iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso) { if (0 == ventoy_plugin_check_path(isodisk, iso)) { grub_printf("image: %s [OK]\n", iso); ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "dud", &pathnum); } else { grub_printf("image: %s [FAIL]\n", iso); } } else { grub_printf("image not found\n"); } } return 0; } static int ventoy_plugin_dud_entry(VTOY_JSON *json, const char *isodisk) { int pathnum = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; dud *node = NULL; dud *next = NULL; file_fullpath *dudpath = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_dud_head) { for (node = g_dud_head; node; node = next) { next = node->next; grub_check_free(node->dudpath); grub_free(node); } g_dud_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso && iso[0] == '/') { if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "dud", &dudpath, &pathnum)) { node = grub_zalloc(sizeof(dud)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); node->dudpath = dudpath; node->dudnum = pathnum; node->files = grub_zalloc(sizeof(dudfile) * pathnum); if (node->files) { if (g_dud_head) { node->next = g_dud_head; } g_dud_head = node; } else { grub_free(node); } } } } } return 0; } static int ventoy_plugin_pwd_entry(VTOY_JSON *json, const char *isodisk) { int i = 0; int len = 0; const char *iso = NULL; const char *pwd = NULL; VTOY_JSON *pNode = NULL; VTOY_JSON *pCNode = NULL; vtoy_password *node = NULL; vtoy_password *tail = NULL; vtoy_password *next = NULL; char bytes[3]; (void)isodisk; if (json->enDataType != JSON_TYPE_OBJECT) { debug("Not object %d\n", json->enDataType); return 0; } if (g_pwd_head) { for (node = g_pwd_head; node; node = next) { next = node->next; grub_free(node); } g_pwd_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->pcName && grub_strcmp("bootpwd", pNode->pcName) == 0) { len = (int)grub_strlen(pNode->unData.pcStrVal); if (len == 64) { g_boot_pwd = 1; for (i = 0; i < 32; i++) { bytes[0] = pNode->unData.pcStrVal[i * 2]; bytes[1] = pNode->unData.pcStrVal[i * 2 + 1]; bytes[2] = 0; g_boot_sha256[i] = (grub_uint8_t)grub_strtoul(bytes, NULL, 16); } } } else if (pNode->pcName && grub_strcmp("menupwd", pNode->pcName) == 0) { for (pCNode = pNode->pstChild; pCNode; pCNode = pCNode->pstNext) { if (pCNode->enDataType != JSON_TYPE_OBJECT) { continue; } iso = vtoy_json_get_string_ex(pCNode->pstChild, "file"); pwd = vtoy_json_get_string_ex(pCNode->pstChild, "pwd"); if (iso && pwd && iso[0] == '/') { node = grub_zalloc(sizeof(vtoy_password)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); len = (int)grub_strlen(pwd); if (len != 64) { grub_free(node); continue; } for (i = 0; i < 32; i++) { bytes[0] = pwd[i * 2]; bytes[1] = pwd[i * 2 + 1]; bytes[2] = 0; node->sha256[i] = (grub_uint8_t)grub_strtoul(bytes, NULL, 16); } if (g_pwd_head) { tail->next = node; } else { g_pwd_head = node; } tail = node; } } } } } return 0; } static int ventoy_plugin_pwd_check(VTOY_JSON *json, const char *isodisk) { int len = 0; const char *iso = NULL; const char *pwd = NULL; VTOY_JSON *pNode = NULL; VTOY_JSON *pCNode = NULL; if (json->enDataType != JSON_TYPE_OBJECT) { grub_printf("Not object %d\n", json->enDataType); return 0; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->pcName && grub_strcmp("bootpwd", pNode->pcName) == 0) { len = (int)grub_strlen(pNode->unData.pcStrVal); if (len != 64) { grub_printf("Invalid bootpwd len :%d\n", len); } else { grub_printf("bootpwd:<%s>\n", pNode->unData.pcStrVal); } } else if (pNode->pcName && grub_strcmp("menupwd", pNode->pcName) == 0) { for (pCNode = pNode->pstChild; pCNode; pCNode = pCNode->pstNext) { if (pCNode->enDataType != JSON_TYPE_OBJECT) { grub_printf("Not object %d\n", pCNode->enDataType); continue; } iso = vtoy_json_get_string_ex(pCNode->pstChild, "file"); if (iso) { if (0 == ventoy_plugin_check_path(isodisk, iso)) { pwd = vtoy_json_get_string_ex(pCNode->pstChild, "pwd"); len = (int)grub_strlen(pwd); if (len != 64) { grub_printf("Invalid sha256 len <%d>\n", len); } else { grub_printf("file:<%s> [OK]\n", iso); grub_printf("pwd:<%s>\n\n", pwd); } } } else { grub_printf("No file found\n"); } } } } return 0; } static int ventoy_plugin_persistence_check(VTOY_JSON *json, const char *isodisk) { int autosel = 0; int pathnum = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array type %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType != JSON_TYPE_OBJECT) { grub_printf("NOT object type\n"); } iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso) { if (0 == ventoy_plugin_check_path(isodisk, iso)) { grub_printf("image: %s [OK]\n", iso); ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "backend", &pathnum); if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) { if (autosel >= 0 && autosel <= pathnum) { grub_printf("autosel: %d [OK]\n", autosel); } else { grub_printf("autosel: %d [FAIL]\n", autosel); } } } else { grub_printf("image: %s [FAIL]\n", iso); } } else { grub_printf("image not found\n"); } } return 0; } static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk) { int autosel = 0; int pathnum = 0; const char *iso = NULL; VTOY_JSON *pNode = NULL; persistence_config *node = NULL; persistence_config *next = NULL; file_fullpath *backendpath = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_persistence_head) { for (node = g_persistence_head; node; node = next) { next = node->next; grub_check_free(node->backendpath); grub_free(node); } g_persistence_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (iso && iso[0] == '/') { if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "backend", &backendpath, &pathnum)) { node = grub_zalloc(sizeof(persistence_config)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); node->backendpath = backendpath; node->backendnum = pathnum; node->autosel = -1; if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) { if (autosel >= 0 && autosel <= pathnum) { node->autosel = autosel; } } if (g_persistence_head) { node->next = g_persistence_head; } g_persistence_head = node; } } } } return 0; } static int ventoy_plugin_menualias_check(VTOY_JSON *json, const char *isodisk) { int type; const char *path = NULL; const char *alias = NULL; VTOY_JSON *pNode = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { type = vtoy_alias_image_file; path = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (!path) { path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); type = vtoy_alias_directory; } alias = vtoy_json_get_string_ex(pNode->pstChild, "alias"); if (path && path[0] == '/' && alias) { if (vtoy_alias_image_file == type) { if (ventoy_is_file_exist("%s%s", isodisk, path)) { grub_printf("image: <%s> [ OK ]\n", path); } else { grub_printf("image: <%s> [ NOT EXIST ]\n", path); } } else { if (ventoy_is_dir_exist("%s%s", isodisk, path)) { grub_printf("dir: <%s> [ OK ]\n", path); } else { grub_printf("dir: <%s> [ NOT EXIST ]\n", path); } } grub_printf("alias: <%s>\n\n", alias); } } return 0; } static int ventoy_plugin_menualias_entry(VTOY_JSON *json, const char *isodisk) { int type; const char *path = NULL; const char *alias = NULL; VTOY_JSON *pNode = NULL; menu_alias *node = NULL; menu_alias *next = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_menu_alias_head) { for (node = g_menu_alias_head; node; node = next) { next = node->next; grub_free(node); } g_menu_alias_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { type = vtoy_alias_image_file; path = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (!path) { path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); type = vtoy_alias_directory; } alias = vtoy_json_get_string_ex(pNode->pstChild, "alias"); if (path && path[0] == '/' && alias) { node = grub_zalloc(sizeof(menu_alias)); if (node) { node->type = type; node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); grub_snprintf(node->alias, sizeof(node->alias), "%s", alias); if (g_menu_alias_head) { node->next = g_menu_alias_head; } g_menu_alias_head = node; } } } return 0; } static int ventoy_plugin_injection_check(VTOY_JSON *json, const char *isodisk) { const char *path = NULL; const char *archive = NULL; VTOY_JSON *pNode = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 0; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { path = vtoy_json_get_string_ex(pNode->pstChild, "image"); if (!path) { grub_printf("image not found\n"); continue; } archive = vtoy_json_get_string_ex(pNode->pstChild, "archive"); if (!archive) { grub_printf("archive not found\n"); continue; } grub_printf("image: <%s> [%s]\n", path, ventoy_check_file_exist("%s%s", isodisk, path) ? "OK" : "NOT EXIST"); grub_printf("archive: <%s> [%s]\n\n", archive, ventoy_check_file_exist("%s%s", isodisk, archive) ? "OK" : "NOT EXIST"); } return 0; } static int ventoy_plugin_injection_entry(VTOY_JSON *json, const char *isodisk) { const char *path = NULL; const char *archive = NULL; VTOY_JSON *pNode = NULL; injection_config *node = NULL; injection_config *next = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_injection_head) { for (node = g_injection_head; node; node = next) { next = node->next; grub_free(node); } g_injection_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { path = vtoy_json_get_string_ex(pNode->pstChild, "image"); archive = vtoy_json_get_string_ex(pNode->pstChild, "archive"); if (path && path[0] == '/' && archive && archive[0] == '/') { node = grub_zalloc(sizeof(injection_config)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); grub_snprintf(node->archive, sizeof(node->archive), "%s", archive); if (g_injection_head) { node->next = g_injection_head; } g_injection_head = node; } } } return 0; } static int ventoy_plugin_menuclass_entry(VTOY_JSON *json, const char *isodisk) { int type; const char *key = NULL; const char *class = NULL; VTOY_JSON *pNode = NULL; menu_class *tail = NULL; menu_class *node = NULL; menu_class *next = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_menu_class_head) { for (node = g_menu_class_head; node; node = next) { next = node->next; grub_free(node); } g_menu_class_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { type = vtoy_class_image_file; key = vtoy_json_get_string_ex(pNode->pstChild, "key"); if (!key) { key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); type = vtoy_class_directory; } class = vtoy_json_get_string_ex(pNode->pstChild, "class"); if (key && class) { node = grub_zalloc(sizeof(menu_class)); if (node) { node->type = type; node->patlen = grub_snprintf(node->pattern, sizeof(node->pattern), "%s", key); grub_snprintf(node->class, sizeof(node->class), "%s", class); if (g_menu_class_head) { tail->next = node; } else { g_menu_class_head = node; } tail = node; } } } return 0; } static int ventoy_plugin_menuclass_check(VTOY_JSON *json, const char *isodisk) { int type; const char *key = NULL; const char *class = NULL; VTOY_JSON *pNode = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { type = vtoy_class_image_file; key = vtoy_json_get_string_ex(pNode->pstChild, "key"); if (!key) { key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); type = vtoy_class_directory; } class = vtoy_json_get_string_ex(pNode->pstChild, "class"); if (key && class) { grub_printf("%s: <%s>\n", (type == vtoy_class_directory) ? "dir" : "key", key); grub_printf("class: <%s>\n\n", class); } } return 0; } static int ventoy_plugin_conf_replace_entry(VTOY_JSON *json, const char *isodisk) { const char *isof = NULL; const char *orgf = NULL; const char *newf = NULL; VTOY_JSON *pNode = NULL; conf_replace *tail = NULL; conf_replace *node = NULL; conf_replace *next = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_conf_replace_head) { for (node = g_conf_replace_head; node; node = next) { next = node->next; grub_free(node); } g_conf_replace_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { isof = vtoy_json_get_string_ex(pNode->pstChild, "iso"); orgf = vtoy_json_get_string_ex(pNode->pstChild, "org"); newf = vtoy_json_get_string_ex(pNode->pstChild, "new"); if (isof && orgf && newf && isof[0] == '/' && orgf[0] == '/' && newf[0] == '/') { node = grub_zalloc(sizeof(conf_replace)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", isof); grub_snprintf(node->orgconf, sizeof(node->orgconf), "%s", orgf); grub_snprintf(node->newconf, sizeof(node->newconf), "%s", newf); if (g_conf_replace_head) { tail->next = node; } else { g_conf_replace_head = node; } tail = node; } } } return 0; } static int ventoy_plugin_conf_replace_check(VTOY_JSON *json, const char *isodisk) { const char *isof = NULL; const char *orgf = NULL; const char *newf = NULL; VTOY_JSON *pNode = NULL; grub_file_t file = NULL; char cmd[256]; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { isof = vtoy_json_get_string_ex(pNode->pstChild, "iso"); orgf = vtoy_json_get_string_ex(pNode->pstChild, "org"); newf = vtoy_json_get_string_ex(pNode->pstChild, "new"); if (isof && orgf && newf && isof[0] == '/' && orgf[0] == '/' && newf[0] == '/') { if (ventoy_check_file_exist("%s%s", isodisk, isof)) { grub_printf("iso:<%s> [OK]\n", isof); grub_snprintf(cmd, sizeof(cmd), "loopback vtisocheck %s%s", isodisk, isof); grub_script_execute_sourcecode(cmd); file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(vtisocheck)/%s", orgf); if (file) { if (grub_strcmp(file->fs->name, "iso9660") == 0) { grub_printf("org:<%s> [OK]\n", orgf); } else { grub_printf("org:<%s> [Exist But NOT ISO9660]\n", orgf); } grub_file_close(file); } else { grub_printf("org:<%s> [NOT Exist]\n", orgf); } grub_script_execute_sourcecode("loopback -d vtisocheck"); } else { grub_printf("iso:<%s> [NOT Exist]\n", isof); grub_printf("org:<%s>\n", orgf); } file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", isodisk, newf); if (file) { if (file->size > vtoy_max_replace_file_size) { grub_printf("new:<%s> [Too Big %lu] \n", newf, (ulong)file->size); } else { grub_printf("new:<%s> [OK]\n", newf); } grub_file_close(file); } else { grub_printf("new:<%s> [NOT Exist]\n", newf); } grub_printf("\n"); } } return 0; } static int ventoy_plugin_auto_memdisk_entry(VTOY_JSON *json, const char *isodisk) { VTOY_JSON *pNode = NULL; auto_memdisk *node = NULL; auto_memdisk *next = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_auto_memdisk_head) { for (node = g_auto_memdisk_head; node; node = next) { next = node->next; grub_free(node); } g_auto_memdisk_head = NULL; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_STRING) { node = grub_zalloc(sizeof(auto_memdisk)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", pNode->unData.pcStrVal); if (g_auto_memdisk_head) { node->next = g_auto_memdisk_head; } g_auto_memdisk_head = node; } } } return 0; } static int ventoy_plugin_auto_memdisk_check(VTOY_JSON *json, const char *isodisk) { VTOY_JSON *pNode = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_STRING) { grub_printf("<%s> ", pNode->unData.pcStrVal); if (ventoy_check_file_exist("%s%s", isodisk, pNode->unData.pcStrVal)) { grub_printf(" [OK]\n"); } else { grub_printf(" [NOT EXIST]\n"); } } } return 0; } static int ventoy_plugin_image_list_entry(VTOY_JSON *json, const char *isodisk) { VTOY_JSON *pNode = NULL; image_list *node = NULL; image_list *next = NULL; image_list *tail = NULL; (void)isodisk; if (json->enDataType != JSON_TYPE_ARRAY) { debug("Not array %d\n", json->enDataType); return 0; } if (g_image_list_head) { for (node = g_image_list_head; node; node = next) { next = node->next; grub_free(node); } g_image_list_head = NULL; } g_plugin_image_list = 1; for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_STRING) { node = grub_zalloc(sizeof(image_list)); if (node) { node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", pNode->unData.pcStrVal); if (g_image_list_head) { tail->next = node; } else { g_image_list_head = node; } tail = node; } } } return 0; } static int ventoy_plugin_image_list_check(VTOY_JSON *json, const char *isodisk) { VTOY_JSON *pNode = NULL; if (json->enDataType != JSON_TYPE_ARRAY) { grub_printf("Not array %d\n", json->enDataType); return 1; } for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) { if (pNode->enDataType == JSON_TYPE_STRING) { grub_printf("<%s> ", pNode->unData.pcStrVal); if (ventoy_check_file_exist("%s%s", isodisk, pNode->unData.pcStrVal)) { grub_printf(" [OK]\n"); } else { grub_printf(" [NOT EXIST]\n"); } } } return 0; } static plugin_entry g_plugin_entries[] = { { "control", ventoy_plugin_control_entry, ventoy_plugin_control_check }, { "theme", ventoy_plugin_theme_entry, ventoy_plugin_theme_check }, { "auto_install", ventoy_plugin_auto_install_entry, ventoy_plugin_auto_install_check }, { "persistence", ventoy_plugin_persistence_entry, ventoy_plugin_persistence_check }, { "menu_alias", ventoy_plugin_menualias_entry, ventoy_plugin_menualias_check }, { "menu_class", ventoy_plugin_menuclass_entry, ventoy_plugin_menuclass_check }, { "injection", ventoy_plugin_injection_entry, ventoy_plugin_injection_check }, { "auto_memdisk", ventoy_plugin_auto_memdisk_entry, ventoy_plugin_auto_memdisk_check }, { "image_list", ventoy_plugin_image_list_entry, ventoy_plugin_image_list_check }, { "conf_replace", ventoy_plugin_conf_replace_entry, ventoy_plugin_conf_replace_check }, { "dud", ventoy_plugin_dud_entry, ventoy_plugin_dud_check }, { "password", ventoy_plugin_pwd_entry, ventoy_plugin_pwd_check }, }; static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk) { int i; char key[128]; VTOY_JSON *cur = json; grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk); while (cur) { for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++) { grub_snprintf(key, sizeof(key), "%s_%s", g_plugin_entries[i].key, g_arch_mode_suffix); if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0 || grub_strcmp(key, cur->pcName) == 0) { debug("Plugin entry for %s\n", g_plugin_entries[i].key); g_plugin_entries[i].entryfunc(cur, isodisk); break; } } cur = cur->pstNext; } return 0; } grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args) { int ret = 0; char *buf = NULL; grub_file_t file; VTOY_JSON *json = NULL; (void)ctxt; (void)argc; file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy.json", args[0]); if (!file) { return GRUB_ERR_NONE; } debug("json configuration file size %d\n", (int)file->size); buf = grub_malloc(file->size + 1); if (!buf) { grub_file_close(file); return 1; } buf[file->size] = 0; grub_file_read(file, buf, file->size); grub_file_close(file); json = vtoy_json_create(); if (!json) { return 1; } ret = vtoy_json_parse(json, buf); if (ret) { grub_env_set("VTOY_PLUGIN_SYNTAX_ERROR", "1"); grub_env_export("VTOY_PLUGIN_SYNTAX_ERROR"); debug("Failed to parse json string %d\n", ret); grub_free(buf); return 1; } ventoy_parse_plugin_config(json->pstChild, args[0]); vtoy_json_destroy(json); grub_free(buf); if (g_boot_pwd) { grub_printf("\n\n\n\n"); if (ventoy_check_password(g_boot_sha256, 3)) { grub_printf("\n!!! Password check failed, will exit after 5 seconds. !!!\n"); grub_refresh(); grub_sleep(5); grub_exit(); } } VENTOY_CMD_RETURN(GRUB_ERR_NONE); } void ventoy_plugin_dump_injection(void) { injection_config *node = NULL; for (node = g_injection_head; node; node = node->next) { grub_printf("\nIMAGE:<%s>\n", node->isopath); grub_printf("ARCHIVE:<%s>\n", node->archive); } return; } void ventoy_plugin_dump_auto_install(void) { int i; install_template *node = NULL; for (node = g_install_template_head; node; node = node->next) { grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->templatenum); for (i = 0; i < node->templatenum; i++) { grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path); } } return; } void ventoy_plugin_dump_persistence(void) { int rc; int i = 0; persistence_config *node = NULL; ventoy_img_chunk_list chunk_list; for (node = g_persistence_head; node; node = node->next) { grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->backendnum); for (i = 0; i < node->backendnum; i++) { grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path); rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list); if (rc == 0) { grub_printf(" [ SUCCESS ]\n"); grub_free(chunk_list.chunk); } else { grub_printf(" [ FAILED ]\n"); } } } return; } install_template * ventoy_plugin_find_install_template(const char *isopath) { int len; install_template *node = NULL; if (!g_install_template_head) { return NULL; } len = (int)grub_strlen(isopath); for (node = g_install_template_head; node; node = node->next) { if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0) { return node; } } return NULL; } char * ventoy_plugin_get_cur_install_template(const char *isopath) { install_template *node = NULL; node = ventoy_plugin_find_install_template(isopath); if ((!node) || (!node->templatepath)) { return NULL; } if (node->cursel < 0 || node->cursel >= node->templatenum) { return NULL; } return node->templatepath[node->cursel].path; } persistence_config * ventoy_plugin_find_persistent(const char *isopath) { int len; persistence_config *node = NULL; if (!g_persistence_head) { return NULL; } len = (int)grub_strlen(isopath); for (node = g_persistence_head; node; node = node->next) { if ((len == node->pathlen) && (grub_strcmp(node->isopath, isopath) == 0)) { return node; } } return NULL; } int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list) { int rc = 1; grub_uint64_t start = 0; grub_file_t file = NULL; persistence_config *node = NULL; node = ventoy_plugin_find_persistent(isopath); if ((!node) || (!node->backendpath)) { return 1; } if (index < 0) { index = node->cursel; } if (index < 0 || index >= node->backendnum) { return 1; } file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->backendpath[index].path); if (!file) { debug("Failed to open file %s%s\n", g_iso_disk_name, node->backendpath[index].path); goto end; } grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list)); chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); if (NULL == chunk_list->chunk) { goto end; } chunk_list->max_chunk = DEFAULT_CHUNK_NUM; chunk_list->cur_chunk = 0; start = file->device->disk->partition->start; ventoy_get_block_list(file, chunk_list, start); if (0 != ventoy_check_block_list(file, chunk_list, start)) { grub_free(chunk_list->chunk); chunk_list->chunk = NULL; goto end; } rc = 0; end: if (file) grub_file_close(file); return rc; } const char * ventoy_plugin_get_injection(const char *isopath) { int len; injection_config *node = NULL; if (!g_injection_head) { return NULL; } len = (int)grub_strlen(isopath); for (node = g_injection_head; node; node = node->next) { if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0) { return node->archive; } } return NULL; } const char * ventoy_plugin_get_menu_alias(int type, const char *isopath) { int len; menu_alias *node = NULL; if (!g_menu_alias_head) { return NULL; } len = (int)grub_strlen(isopath); for (node = g_menu_alias_head; node; node = node->next) { if (node->type == type && node->pathlen && node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0) { return node->alias; } } return NULL; } const char * ventoy_plugin_get_menu_class(int type, const char *name) { int len; menu_class *node = NULL; if (!g_menu_class_head) { return NULL; } len = (int)grub_strlen(name); if (vtoy_class_image_file == type) { for (node = g_menu_class_head; node; node = node->next) { if (node->type == type && node->patlen <= len && grub_strstr(name, node->pattern)) { return node->class; } } } else { for (node = g_menu_class_head; node; node = node->next) { if (node->type == type && node->patlen == len && grub_strncmp(name, node->pattern, len) == 0) { return node->class; } } } return NULL; } int ventoy_plugin_check_memdisk(const char *isopath) { int len; auto_memdisk *node = NULL; if (!g_auto_memdisk_head) { return 0; } len = (int)grub_strlen(isopath); for (node = g_auto_memdisk_head; node; node = node->next) { if (node->pathlen == len && grub_strncmp(isopath, node->isopath, len) == 0) { return 1; } } return 0; } int ventoy_plugin_get_image_list_index(int type, const char *name) { int len; int index = 1; image_list *node = NULL; if (!g_image_list_head) { return 0; } len = (int)grub_strlen(name); for (node = g_image_list_head; node; node = node->next, index++) { if (vtoy_class_directory == type) { if (len < node->pathlen && grub_strncmp(name, node->isopath, len) == 0) { return index; } } else { if (len == node->pathlen && grub_strncmp(name, node->isopath, len) == 0) { return index; } } } return 0; } conf_replace * ventoy_plugin_find_conf_replace(const char *iso) { int len; conf_replace *node; if (!g_conf_replace_head) { return NULL; } len = (int)grub_strlen(iso); for (node = g_conf_replace_head; node; node = node->next) { if (node->pathlen == len && grub_strncmp(iso, node->isopath, len) == 0) { return node; } } return NULL; } dud * ventoy_plugin_find_dud(const char *iso) { int len; dud *node; if (!g_dud_head) { return NULL; } len = (int)grub_strlen(iso); for (node = g_dud_head; node; node = node->next) { if (node->pathlen == len && grub_strncmp(iso, node->isopath, len) == 0) { return node; } } return NULL; } int ventoy_plugin_load_dud(dud *node, const char *isopart) { int i; char *buf; grub_file_t file; for (i = 0; i < node->dudnum; i++) { if (node->files[i].size > 0) { debug("file %d has been loaded\n", i); continue; } file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", isopart, node->dudpath[i].path); if (file) { buf = grub_malloc(file->size); if (buf) { grub_file_read(file, buf, file->size); node->files[i].size = (int)file->size; node->files[i].buf = buf; } grub_file_close(file); } } return 0; } static const grub_uint8_t * ventoy_plugin_get_password(const char *isopath) { int len; vtoy_password *node = NULL; if ((!g_pwd_head) || (!isopath)) { return NULL; } len = (int)grub_strlen(isopath); for (node = g_pwd_head; node; node = node->next) { if (node->pathlen == len && grub_strncmp(isopath, node->isopath, len) == 0) { return node->sha256; } } return NULL; } int ventoy_check_password(const grub_uint8_t *pwdsha256, int retry) { char input[128]; grub_uint8_t sha256[32]; while (retry--) { grub_memset(input, 0, sizeof(input)); grub_printf("Enter password: "); grub_refresh(); grub_password_get(input, sizeof(input)); grub_crypto_hash(GRUB_MD_SHA256, sha256, input, grub_strlen(input)); if (grub_memcmp(pwdsha256, sha256, 32) == 0) { return 0; } else { grub_printf("Invalid password!\n\n"); grub_refresh(); } } return 1; } grub_err_t ventoy_cmd_check_password(grub_extcmd_context_t ctxt, int argc, char **args) { int ret; const grub_uint8_t *sha256 = NULL; (void)ctxt; (void)argc; sha256 = ventoy_plugin_get_password(args[0]); if (sha256) { if (0 == ventoy_check_password(sha256, 1)) { ret = 1; } else { ret = 0; } } else { ret = 1; } grub_errno = 0; return ret; } grub_err_t ventoy_cmd_plugin_check_json(grub_extcmd_context_t ctxt, int argc, char **args) { int i = 0; int ret = 0; char *buf = NULL; char key[128]; grub_file_t file; VTOY_JSON *node = NULL; VTOY_JSON *json = NULL; (void)ctxt; if (argc != 3) { return 0; } file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy.json", args[0]); if (!file) { grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\n"); grub_printf("Attention: directory name and filename are both case-sensitive.\n"); goto end; } buf = grub_malloc(file->size + 1); if (!buf) { grub_printf("Failed to malloc memory %lu.\n", (ulong)(file->size + 1)); goto end; } buf[file->size] = 0; grub_file_read(file, buf, file->size); json = vtoy_json_create(); if (!json) { grub_printf("Failed to create json\n"); goto end; } ret = vtoy_json_parse(json, buf); if (ret) { grub_printf("Syntax error detected in ventoy.json, please check it.\n"); goto end; } grub_snprintf(key, sizeof(key), "%s_%s", args[1], g_arch_mode_suffix); for (node = json->pstChild; node; node = node->pstNext) { if (grub_strcmp(node->pcName, args[1]) == 0 || grub_strcmp(node->pcName, key) == 0) { break; } } if (!node) { grub_printf("%s is NOT found in ventoy.json\n", args[1]); goto end; } for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++) { if (grub_strcmp(g_plugin_entries[i].key, args[1]) == 0) { if (g_plugin_entries[i].checkfunc) { ret = g_plugin_entries[i].checkfunc(node, args[2]); } break; } } end: check_free(file, grub_file_close); check_free(json, vtoy_json_destroy); grub_check_free(buf); return 0; }