// SPDX-License-Identifier: MPL-2.0 #ifndef VYBUILD_LIB_H #define VYBUILD_LIB_H #include #include #include #include #include #include #include #include #include "json.hpp" #include "xxhash.h" #include using json=nlohmann::json; namespace fs=std::filesystem; const std::string syntax_version="0.1"; const std::vector threaded_actions={"run_submodule","run_submodule_if","run_actions_parallel","vyld_compilation","run_submodule_parallel","compile_multiple_cpp"}; namespace vybuild { namespace fat32 { void load_crypto_lib(std::string path); bool is_crypto_lib_loaded(); bool is_vftm_target_set(); uint8_t* get_manifest_keypair_buffer(); void create_fat32(std::string key,size_t size); void add_directory_fat32(std::string key,std::string full_path); void add_file_fat32(std::string key,std::string full_path,uint8_t *buffer_in,size_t file_size,bool is_vftm_target); std::vector export_fat32(std::string key,bool generate_vftm,std::string disk_guid_var,std::string efi_part_unique_guid_var); } namespace disk { std::array uuid4_to_bytes(const std::string& uuid); void create_disk(std::string key,size_t size,std::string disk_guid); void add_partition(std::string key,size_t partition_size_bytes,std::string type_guid,std::string unique_guid,uint64_t attributes,std::string name,uint8_t* in_buf,size_t in_size); std::vector export_disk(std::string key); } namespace condition { bool evaluate_condition(const json& condition); } namespace parser { std::string root_folder_parsing(const std::string& root_folder,const std::string& file); std::vector vector_string_vars(std::vector vector_in); std::string string_vars(std::string string_in); std::vector vector_string_path_completions(std::vector vector_in,std::string suffix); } namespace vars { std::vector& get_global_variables_list(); void set_global_variable(std::string key,std::string value); std::string get_global_variable(std::string key); } namespace cache { void init_cache(bool enable_smart_cache); void store_file(std::string key,fs::path file_path); bool cache_contains(std::string key); void extract_file(std::string key,fs::path output_path); void clean_cache(); std::string xxhash_to_string(XXH128_hash_t hash); } namespace actions { void check_arg_string(const json& args,std::string field_name); void check_arg_vector_string(const json& args,std::string field_name); enum class ActionStatus { Success, Fail, SystemError, ExitSuccess, ExitFail }; class RunSubmoduleAction { public: RunSubmoduleAction(const json& args,std::string root_folder) { char path[PATH_MAX]; getcwd(path,sizeof(path)); chdir(root_folder.c_str()); check_arg_string(args,"file"); if (!args.contains("wait")) throw std::runtime_error("Wait isn't provided."); if (!args["wait"].is_boolean()) throw std::runtime_error("Wait isn't a boolean"); if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided."); if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean"); this->file_variables=args["file_variables"].get(); this->file=args["file"].get(); this->wait=args["wait"].get(); this->block_if_fail=args["block_if_fail"].get(); chdir(path); } bool file_variables; std::string file; bool wait; bool block_if_fail; ActionStatus run_action(); }; class RunCommandWaitAction { public: RunCommandWaitAction(const json& args) { check_arg_vector_string(args,"command"); if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided."); if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string"); if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") { throw std::runtime_error("\""+args["show_output"].get()+"\" isn't a valid output mode."); } if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); this->command_variables=args["command_variables"].get(); this->command=args["command"].get>(); this->show_output=args["show_output"].get(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); } bool command_variables; std::vector command; std::string show_output; std::vector success_status; bool ignore_success_status; ActionStatus run_action(); }; class SaveCommandContentAction { public: SaveCommandContentAction(const json& args) { check_arg_vector_string(args,"command"); if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); check_arg_string(args,"command_output_file"); this->command_variables=args["command_variables"].get(); this->command=args["command"].get>(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); this->command_output_file_variables=args["command_output_file_variables"].get(); this->command_output_file=args["command_output_file"].get(); } bool command_variables; std::vector command; std::vector success_status; bool ignore_success_status; bool command_output_file_variables; std::string command_output_file; ActionStatus run_action(); }; class CompileOneAsmAction { public: CompileOneAsmAction(const json& args) { check_arg_string(args,"source"); check_arg_string(args,"assembler"); check_arg_vector_string(args,"pre_arguments"); check_arg_vector_string(args,"post_arguments"); check_arg_string(args,"output_file"); if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided."); if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean"); this->source_variables=args["source_variables"].get(); this->assembler_variables=args["assembler_variables"].get(); this->pre_arguments_variables=args["pre_arguments_variables"].get(); this->post_arguments_variables=args["post_arguments_variables"].get(); this->output_file_variables=args["output_file_variables"].get(); this->source=args["source"].get(); this->assembler=args["assembler"].get(); this->output_file=args["output_file"].get(); this->pre_arguments=args["pre_arguments"].get>(); this->post_arguments=args["post_arguments"].get>(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); this->cache_authorized=args["cache_authorized"].get(); } bool source_variables; std::string source; bool assembler_variables; std::string assembler; bool pre_arguments_variables; std::vector pre_arguments; bool post_arguments_variables; std::vector post_arguments; bool output_file_variables; std::string output_file; std::vector success_status; bool ignore_success_status; bool cache_authorized; ActionStatus run_action(); }; class EnsureFolderExistenceAction { public: EnsureFolderExistenceAction(const json& args) { check_arg_string(args,"path"); this->path_variables=args["path_variables"].get(); this->path=args["path"].get(); } bool path_variables; std::string path; ActionStatus run_action(); }; class MoveFileAction { public: MoveFileAction(const json& args) { check_arg_string(args,"source_file"); check_arg_string(args,"destination_folder"); this->source_file_variables=args["source_file_variables"].get(); this->source_file=args["source_file"].get(); this->destination_folder_variables=args["destination_folder_variables"].get(); this->destination_folder=args["destination_folder"].get(); } bool source_file_variables; std::string source_file; bool destination_folder_variables; std::string destination_folder; ActionStatus run_action(); }; class CompileOneCppAction { public: CompileOneCppAction(const json& args) { check_arg_string(args,"source"); check_arg_string(args,"compiler"); check_arg_vector_string(args,"pre_arguments"); check_arg_vector_string(args,"post_arguments"); check_arg_string(args,"output_file"); check_arg_string(args,"headers_command"); if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided."); if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean"); this->source_variables=args["source_variables"].get(); this->compiler_variables=args["compiler_variables"].get(); this->pre_arguments_variables=args["pre_arguments_variables"].get(); this->post_arguments_variables=args["post_arguments_variables"].get(); this->output_file_variables=args["output_file_variables"].get(); this->headers_command_variables=args["headers_command_variables"].get(); this->source=args["source"].get(); this->compiler=args["compiler"].get(); this->output_file=args["output_file"].get(); this->pre_arguments=args["pre_arguments"].get>(); this->post_arguments=args["post_arguments"].get>(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); this->cache_authorized=args["cache_authorized"].get(); this->headers_command=args["headers_command"].get(); } bool source_variables; std::string source; bool compiler_variables; std::string compiler; bool pre_arguments_variables; std::vector pre_arguments; bool post_arguments_variables; std::vector post_arguments; bool output_file_variables; std::string output_file; std::vector success_status; bool ignore_success_status; bool cache_authorized; bool headers_command_variables; std::string headers_command; ActionStatus run_action(); }; class RunSubmoduleIfAction { public: RunSubmoduleIfAction(const json& args,std::string root_folder) { char path[PATH_MAX]; getcwd(path,sizeof(path)); chdir(root_folder.c_str()); check_arg_string(args,"file"); if (!args.contains("wait")) throw std::runtime_error("Wait isn't provided."); if (!args["wait"].is_boolean()) throw std::runtime_error("Wait isn't a boolean"); if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided."); if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean"); if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided."); if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary."); this->condition=args["condition"]; this->file=args["file"].get(); this->file=fs::absolute(fs::path(args["file"].get())); this->wait=args["wait"].get(); this->block_if_fail=args["block_if_fail"].get(); chdir(path); } json condition; bool file_variables; std::string file; bool wait; bool block_if_fail; ActionStatus run_action(); }; class RunCommandWaitDirAction { public: RunCommandWaitDirAction(const json& args) { check_arg_vector_string(args,"command"); check_arg_string(args,"working_dir"); if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided."); if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string"); if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") { throw std::runtime_error("\""+args["show_output"].get()+"\" isn't a valid output mode."); } if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); this->command_variables=args["command_variables"].get(); this->command=args["command"].get>(); this->show_output=args["show_output"].get(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); this->working_dir_variables=args["working_dir_variables"].get(); this->working_dir=args["working_dir"].get(); } bool command_variables; std::vector command; std::string show_output; std::vector success_status; bool ignore_success_status; bool working_dir_variables; std::string working_dir; ActionStatus run_action(); }; class CopyFolderAction { public: CopyFolderAction(const json& args) { check_arg_string(args,"source_folder"); check_arg_string(args,"destination_folder"); this->source_folder_variables=args["source_folder_variables"].get(); this->source_folder=args["source_folder"].get(); this->destination_folder_variables=args["destination_folder_variables"].get(); this->destination_folder=args["destination_folder"].get(); } bool source_folder_variables; std::string source_folder; bool destination_folder_variables; std::string destination_folder; ActionStatus run_action(); }; class ExtractFromCacheAction { public: ExtractFromCacheAction(const json& args) { check_arg_string(args,"target"); check_arg_string(args,"output_file"); this->target_variables=args["target_variables"].get(); this->output_file_variables=args["output_file_variables"].get(); this->target=args["target"].get(); this->output_file=args["output_file"].get(); } bool target_variables; std::string target; bool output_file_variables; std::string output_file; ActionStatus run_action(); }; class StoreInCacheAction { public: StoreInCacheAction(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"file"); this->key_variables=args["key_variables"].get(); this->file_variables=args["file_variables"].get(); this->overwrite_allowed=args["overwrite_allowed"].get(); this->key=args["key"].get(); this->file=args["file"].get(); } bool key_variables; std::string key; bool file_variables; std::string file; bool overwrite_allowed; ActionStatus run_action(); }; class EnsureFolderResetAction { public: EnsureFolderResetAction(const json& args) { check_arg_string(args,"path"); this->path_variables=args["path_variables"].get(); this->path=args["path"].get(); } bool path_variables; std::string path; ActionStatus run_action(); }; class RunActionsIfAction { public: RunActionsIfAction(const json& args,bool is_threading_allowed,std::string root_folder) { if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided."); if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary."); if (!args["actions"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list."); for (const auto& act:args["actions"]) { if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary."); if (!act.contains("action")) throw std::runtime_error("Action isn't provided."); if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string."); if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction."); if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided."); if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary."); actions.push_back(act); } this->condition=args["condition"]; this->is_threading_allowed=is_threading_allowed; this->root_folder=root_folder; } json condition; std::vector actions; bool is_threading_allowed; std::string root_folder; ActionStatus run_action(); }; class RunActionsIfElseAction { public: RunActionsIfElseAction(const json& args,bool is_threading_allowed,std::string root_folder) { if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided."); if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary."); if (!args.contains("actions_if")) throw std::runtime_error("No actions are provided."); if (!args["actions_if"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list."); for (const auto& act:args["actions_if"]) { if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary."); if (!act.contains("action")) throw std::runtime_error("Action isn't provided."); if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string."); if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction."); if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided."); if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary."); actions_if.push_back(act); } if (!args.contains("actions_else")) throw std::runtime_error("No actions are provided."); if (!args["actions_else"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list."); for (const auto& act:args["actions_else"]) { if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary."); if (!act.contains("action")) throw std::runtime_error("Action isn't provided."); if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string."); if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction."); if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided."); if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary."); actions_else.push_back(act); } this->condition=args["condition"]; this->is_threading_allowed=is_threading_allowed; this->root_folder=root_folder; } json condition; std::vector actions_if; std::vector actions_else; bool is_threading_allowed; std::string root_folder; ActionStatus run_action(); }; class RunCommandStrAction { public: RunCommandStrAction(const json& args) { check_arg_string(args,"command"); if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided."); if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string"); if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") { throw std::runtime_error("\""+args["show_output"].get()+"\" isn't a valid output mode."); } if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); this->command_variables=args["command_variables"].get(); this->command=args["command"].get(); this->show_output=args["show_output"].get(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); } bool command_variables; std::string command; std::string show_output; std::vector success_status; bool ignore_success_status; ActionStatus run_action(); }; class ComputeElementHashAction { public: ComputeElementHashAction(const json& args) { check_arg_string(args,"element"); if (!args.contains("output_variable")) throw std::runtime_error("Output variable isn't provided."); if (!args["output_variable"].is_string()) throw std::runtime_error("Output variable isn't a string."); this->element_variables=args["element_variables"].get(); this->element=args["element"].get(); this->output_variable=args["output_variable"].get(); } bool element_variables; std::string element; std::string output_variable; ActionStatus run_action(); }; class CompileMultipleCppAction { public: CompileMultipleCppAction(const json& args) { check_arg_vector_string(args,"source_files"); check_arg_string(args,"compiler"); check_arg_vector_string(args,"pre_arguments"); check_arg_vector_string(args,"post_arguments"); check_arg_vector_string(args,"output_files"); check_arg_string(args,"headers_command"); if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided."); if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean"); if (!args.contains("source_files_path_completion")) throw std::runtime_error("Source files path completion isn't provided."); if (!args["source_files_path_completion"].is_boolean()) throw std::runtime_error("Source files path completion isn't a boolean"); this->source_files_path_completion=args["source_files_path_completion"].get(); if (this->source_files_path_completion) { if (!args.contains("path_completion_source_ext")) throw std::runtime_error("Path completion sources extension isn't provided"); if (!args["path_completion_source_ext"].is_string()) throw std::runtime_error("Path completion sources extension isn't a string"); if (!args.contains("path_completion_output_ext")) throw std::runtime_error("Path completion output extension isn't provided"); if (!args["path_completion_output_ext"].is_string()) throw std::runtime_error("Path completion output extension isn't a string"); this->path_completion_source_ext=args["path_completion_source_ext"].get(); this->path_completion_output_ext=args["path_completion_output_ext"].get(); } this->source_files_variables=args["source_files_variables"].get(); this->compiler_variables=args["compiler_variables"].get(); this->pre_arguments_variables=args["pre_arguments_variables"].get(); this->post_arguments_variables=args["post_arguments_variables"].get(); this->output_files_variables=args["output_files_variables"].get(); this->ignore_success_status=args["ignore_success_status"].get(); this->cache_authorized=args["cache_authorized"].get(); this->headers_command_variables=args["headers_command_variables"].get(); this->compiler=args["compiler"].get(); this->headers_command=args["headers_command"].get(); this->source_files=args["source_files"].get>(); this->pre_arguments=args["pre_arguments"].get>(); this->post_arguments=args["post_arguments"].get>(); this->output_files=args["output_files"].get>(); this->success_status=args["success_status"].get>(); } bool source_files_path_completion; bool source_files_variables; std::vector source_files; bool compiler_variables; std::string compiler; bool pre_arguments_variables; std::vector pre_arguments; bool post_arguments_variables; std::vector post_arguments; bool output_files_variables; std::vector output_files; std::vector success_status; bool ignore_success_status; bool cache_authorized; bool headers_command_variables; std::string headers_command; std::string path_completion_source_ext; std::string path_completion_output_ext; ActionStatus run_action(); }; class CopyFileAction { public: CopyFileAction(const json& args) { check_arg_string(args,"source_file"); check_arg_string(args,"destination_folder"); this->source_file_variables=args["source_file_variables"].get(); this->source_file=args["source_file"].get(); this->destination_folder_variables=args["destination_folder_variables"].get(); this->destination_folder=args["destination_folder"].get(); } bool source_file_variables; std::string source_file; bool destination_folder_variables; std::string destination_folder; ActionStatus run_action(); }; class CreateFat32Action { public: CreateFat32Action(const json& args) { check_arg_string(args,"key"); if (!args.contains("size")) throw std::runtime_error("Size isn't provided."); if (!args["size"].is_number_unsigned()) throw std::runtime_error("Size isn't an integer."); this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->size=args["size"].get(); } bool key_variables; std::string key; size_t size; ActionStatus run_action(); }; class CreateFolderFat32Action { public: CreateFolderFat32Action(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"full_path"); this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->full_path_variables=args["full_path_variables"].get(); this->full_path=args["full_path"].get(); } bool key_variables; std::string key; bool full_path_variables; std::string full_path; ActionStatus run_action(); }; class CreateFileFat32Action { public: CreateFileFat32Action(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"source_path"); check_arg_string(args,"full_path"); if (args.contains("is_vftm_target")) { if (!args["is_vftm_target"].is_boolean()) throw std::runtime_error("Is VFTM target isn't an boolean."); this->is_vftm_target=args["is_vftm_target"].get(); } this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->source_path_variables=args["source_path_variables"].get(); this->source_path=args["source_path"].get(); this->full_path_variables=args["full_path_variables"].get(); this->full_path=args["full_path"].get(); } bool is_vftm_target=false; bool key_variables; std::string key; bool source_path_variables; std::string source_path; bool full_path_variables; std::string full_path; ActionStatus run_action(); }; class ExportFat32Action { public: ExportFat32Action(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"export_path"); if (!args.contains("generate_vftm")) throw std::runtime_error("Generate VFTM isn't provided."); if (!args["generate_vftm"].is_boolean()) throw std::runtime_error("Generate VFTM isn't a boolean."); this->generate_vftm=args["generate_vftm"].get(); if (this->generate_vftm) { if (!args.contains("disk_guid_var")) throw std::runtime_error("Disk GUID variable must be provided when generate_vftm is true."); if (!args["disk_guid_var"].is_string()) throw std::runtime_error("Disk GUID variable must be a string."); if (!args.contains("efi_part_unique_guid_var")) throw std::runtime_error("EFI partition unique GUID variable must be provided when generate_vftm is true."); if (!args["efi_part_unique_guid_var"].is_string()) throw std::runtime_error("EFI partition unique GUID variable must be a boolean."); this->disk_guid_var=args["disk_guid_var"].get(); this->efi_part_unique_guid_var=args["efi_part_unique_guid_var"].get(); } this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->export_path_variables=args["export_path_variables"].get(); this->export_path=args["export_path"].get(); } bool key_variables; std::string key; bool export_path_variables; std::string export_path; bool generate_vftm; std::string disk_guid_var; std::string efi_part_unique_guid_var; ActionStatus run_action(); }; class CreateDiskAction { public: CreateDiskAction(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"disk_guid"); if (!args.contains("size")) throw std::runtime_error("Size isn't provided."); if (!args["size"].is_number_unsigned()) throw std::runtime_error("Size isn't an integer."); this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->disk_guid_variables=args["disk_guid_variables"].get(); this->disk_guid=args["disk_guid"].get(); this->size=args["size"].get(); } bool key_variables; std::string key; size_t size; bool disk_guid_variables; std::string disk_guid; ActionStatus run_action(); }; class AddPartitionDiskAction { public: AddPartitionDiskAction(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"type_guid"); check_arg_string(args,"unique_guid"); check_arg_string(args,"name"); check_arg_string(args,"source_file"); this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->type_guid_variables=args["type_guid_variables"].get(); this->type_guid=args["type_guid"].get(); this->unique_guid_variables=args["unique_guid_variables"].get(); this->unique_guid=args["unique_guid"].get(); this->name_variables=args["name_variables"].get(); this->name=args["name"].get(); this->source_file_variables=args["source_file_variables"].get(); this->source_file=args["source_file"].get(); } bool key_variables; std::string key; bool type_guid_variables; std::string type_guid; bool unique_guid_variables; std::string unique_guid; bool name_variables; std::string name; bool source_file_variables; std::string source_file; ActionStatus run_action(); }; class ExportDiskAction { public: ExportDiskAction(const json& args) { check_arg_string(args,"key"); check_arg_string(args,"export_path"); this->key_variables=args["key_variables"].get(); this->key=args["key"].get(); this->export_path_variables=args["export_path_variables"].get(); this->export_path=args["export_path"].get(); } bool key_variables; std::string key; bool export_path_variables; std::string export_path; ActionStatus run_action(); }; class VFTMLoadCryptoLibAction { public: VFTMLoadCryptoLibAction(const json& args) { check_arg_string(args,"lib_path"); this->lib_path_variables=args["lib_path_variables"].get(); this->lib_path=args["lib_path"].get(); } bool lib_path_variables; std::string lib_path; ActionStatus run_action(); }; class VFTMRunKeysGeneratorAction { public: VFTMRunKeysGeneratorAction(const json& args) { check_arg_vector_string(args,"command"); check_arg_string(args,"working_dir"); check_arg_string(args,"socket_path"); if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided."); if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean"); for (auto& arg:args["success_status"]) { if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer."); } if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided."); if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean"); this->command_variables=args["command_variables"].get(); this->command=args["command"].get>(); this->socket_path_variables=args["socket_path_variables"].get(); this->socket_path=args["socket_path"].get(); this->success_status=args["success_status"].get>(); this->ignore_success_status=args["ignore_success_status"].get(); this->working_dir_variables=args["working_dir_variables"].get(); this->working_dir=args["working_dir"].get(); } bool command_variables; std::vector command; bool socket_path_variables; std::string socket_path; std::vector success_status; bool ignore_success_status; bool working_dir_variables; std::string working_dir; ActionStatus run_action(); }; using ParallelAction=std::variant; ParallelAction return_pararrel_action(const json& args,std::string action_name); class RunActionsParallelAction { public: RunActionsParallelAction (const json& args) { if (!args.contains("actions")) throw std::runtime_error("No actions are provided."); if (!args["actions"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list."); for (const auto& act:args["actions"]) { if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary."); if (!act.contains("action")) throw std::runtime_error("Action isn't provided."); if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string."); if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided."); if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary."); actions.push_back(return_pararrel_action(act["args"],act["action"])); } } std::vector actions; ActionStatus run_action(); }; class RunSubmoduleParallelAction { public: RunSubmoduleParallelAction(const json& args) { check_arg_vector_string(args,"submodules"); for (const auto& act:args["submodules"]) { submodules.push_back(act.get()); } this->submodules_variables=args["submodules_variables"].get(); } bool submodules_variables; std::vector submodules; ActionStatus run_action(); }; class VyldCompilationAction { public: VyldCompilationAction(const json& args) { check_arg_vector_string(args,"source_files"); check_arg_vector_string(args,"source_asm"); check_arg_string(args,"compiler"); check_arg_string(args,"assembler"); check_arg_string(args,"linker"); check_arg_string(args,"compiler_flags"); check_arg_string(args,"output_file"); check_arg_string(args,"headers_command"); if (!args.contains("source_files_path_completion")) throw std::runtime_error("Source file path completion isn't provided."); if (!args["source_files_path_completion"].is_boolean()) throw std::runtime_error("Source file path completion isn't a boolean."); if (!args.contains("source_asm_path_completion")) throw std::runtime_error("Source ASM path completion isn't provided."); if (!args["source_asm_path_completion"].is_boolean()) throw std::runtime_error("Source ASM path completion isn't a boolean."); if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided."); if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean."); if (!args.contains("object_files_cache_authorized")) throw std::runtime_error("Object files caching authorized isn't provided."); if (!args["object_files_cache_authorized"].is_boolean()) throw std::runtime_error("Object files caching authorized isn't a boolean."); if (!args.contains("payloads")) throw std::runtime_error("Payloads aren't provided."); if (!args["payloads"].is_array()) throw std::runtime_error("Payloads aren't stored in a list."); this->source_files_path_completion=args["source_files_path_completion"].get(); this->source_asm_path_completion=args["source_asm_path_completion"].get(); this->source_files_variables=args["source_files_variables"].get(); this->source_asm_variables=args["source_asm_variables"].get(); this->compiler_variables=args["compiler_variables"].get(); this->assembler_variables=args["assembler_variables"].get(); this->linker_variables=args["linker_variables"].get(); this->compiler_flags_variables=args["compiler_flags_variables"].get(); this->output_file_variables=args["output_file_variables"].get(); this->block_if_fail=args["block_if_fail"].get(); this->object_files_cache_authorized=args["object_files_cache_authorized"].get(); this->headers_command_variables=args["headers_command_variables"].get(); this->source_files=args["source_files"].get>(); this->source_asm=args["source_asm"].get>(); this->compiler=args["compiler"].get(); this->assembler=args["assembler"].get(); this->linker=args["linker"].get(); this->compiler_flags=args["compiler_flags"].get(); this->output_file=args["output_file"].get(); this->headers_command=args["headers_command"].get(); this->payloads=args["payloads"].get>(); } bool source_files_path_completion; bool source_files_variables; std::vector source_files; bool compiler_variables; std::string compiler; bool source_asm_path_completion; bool source_asm_variables; std::vector source_asm; bool assembler_variables; std::string assembler; bool linker_variables; std::string linker; bool compiler_flags_variables; std::string compiler_flags; bool output_file_variables; std::string output_file; bool block_if_fail; bool object_files_cache_authorized; bool headers_command_variables; std::string headers_command; std::vector payloads; ActionStatus run_action(); }; using Action=std::variant; Action return_action(const json &args,std::string action_name,bool is_threading_allowed,std::string root_folder); } namespace module { class Module { public: Module(std::string file,bool is_threading_allowed) { std::ifstream f(file); if (!f) { throw std::runtime_error(file+" couldn't be opened."); } json j=json::parse(f); if (!j.contains("version")) throw std::runtime_error("Syntax version isn't provided."); if (!j["version"].is_string()) throw std::runtime_error("Syntax version isn't a string."); if (j["version"]!=syntax_version) throw std::runtime_error("Syntax version is "+j["version"].get()+". Expected "+syntax_version+"."); if (j.contains("root_folder")) { if (!j["root_folder"].is_string()) throw std::runtime_error("Root folder isn't a string."); this->root_folder=vybuild::parser::root_folder_parsing(j["root_folder"].get(),file); } else { this->root_folder=vybuild::parser::root_folder_parsing("%filefolder%",file); } if (!j.contains("run_context")) throw std::runtime_error("Run context isn't provided."); if (!j["run_context"].is_string()) throw std::runtime_error("Run context isn't a string."); if (j["run_context"]!="root" && j["run_context"]!="sub" && j["run_context"]!="both") throw std::runtime_error("\""+j["run_context"].get()+"\" isn't a string."); this->run_context=j["run_context"].get(); if (!j.contains("name")) throw std::runtime_error("Name isn't provided."); if (!j["name"].is_string()) throw std::runtime_error("Name isn't a string."); this->name=j["name"].get(); if (this->run_context=="root" && j.contains("global_vars")) { if (!j["global_vars"].is_object()) throw std::runtime_error("Global variables aren't in a list."); for (const auto& [var_name,value]:j["global_vars"].items()) { vybuild::vars::set_global_variable("\\$"+var_name+"\\$",value); } } else if (this->run_context!="root" && j.contains("global_vars")){ throw std::runtime_error("Global variables are only available for modules that are guaranteed to be runned as root."); } if (this->run_context=="root" && j.contains("global_uuid")) { if (!j["global_uuid"].is_array()) throw std::runtime_error("Global UUID aren't in a list."); for (const auto& var_name:j["global_uuid"].items()) { uuid_t id; uuid_generate_random(id); char out[37]; uuid_unparse_lower(id,out); vybuild::vars::set_global_variable("\\$"+var_name.value().get()+"\\$",std::string(out)); } } else if (this->run_context!="root" && j.contains("global_uuid")){ throw std::runtime_error("Global UUID are only available for modules that are guaranteed to be runned as root."); } if (!j.contains("actions")) throw std::runtime_error("Couldn't find any action inside module."); if (!j["actions"].is_array()) throw std::runtime_error("Actions aren't in a list."); for (const auto& act:j["actions"]) { if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary."); if (!act.contains("action")) throw std::runtime_error("Action isn't provided."); if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string."); if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided."); if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary."); actions.push_back(vybuild::actions::return_action(act["args"],act["action"],is_threading_allowed,this->root_folder)); } } std::string root_folder; std::string run_context; std::string name; std::vector actions; vybuild::actions::ActionStatus run_module(bool is_root,bool is_threaded) { if (this->run_context=="root" && !is_root) { throw std::runtime_error("Module isn't supposed to be ran as a submodule."); } else if (this->run_context=="sub" && is_root) { throw std::runtime_error("Module isn't supposed to be ran as root module."); } if (is_threaded) unshare(CLONE_FS); char path[PATH_MAX]; getcwd(path,sizeof(path)); chdir(this->root_folder.c_str()); for (auto& a:actions) { vybuild::actions::ActionStatus status=std::visit([](auto& act) { return act.run_action(); },a); if (status!=vybuild::actions::ActionStatus::Success && status!=vybuild::actions::ActionStatus::ExitSuccess) { chdir(path); return status; } if (status==vybuild::actions::ActionStatus::ExitSuccess) { chdir(path); return vybuild::actions::ActionStatus::Success; } } chdir(path); return vybuild::actions::ActionStatus::Success; } }; } } #endif