#include "version.hpp" #include "config.hpp" #include "service_runner.hpp" #include "services.hpp" #include "servers.hpp" #include "utils/directories.hpp" #include "templates.hpp" #include "utils/utils.hpp" #include "autocomplete.hpp" #include "utils/hash.hpp" #include "command_registry.hpp" #include #include #include #include #include #include #include #include #include namespace dropshell { extern const std::string VERSION; extern const std::string RELEASE_DATE; extern const std::string AUTHOR; extern const std::string LICENSE; int main(int argc, char* argv[]) { try { // silently attempt to load the config file and templates. gConfig().load_config(); if (gConfig().is_config_set()) gTemplateManager().load_sources(); // process the command line arguments. std::vector args(argv, argv + argc); if (args.size() < 2) args.push_back("help"); ASSERT(args.size() > 1, "No command provided, logic error."); CommandContext ctx{args[0], args[1], std::vector(args.begin() + 2, args.end())}; if (ctx.command == "autocomplete") { CommandRegistry::instance().autocomplete(ctx); return 0; } const CommandInfo* info = CommandRegistry::instance().find_command(ctx.command); if (!info) { std::cerr << "Unknown command: " << ctx.command << std::endl; return 1; } if (info->requires_config && !gConfig().is_config_set()) { std::cerr << "Valid dropshell configuration required for command: " << ctx.command << std::endl; std::cerr << "Please run 'dropshell edit' to set up the dropshell configuration." << std::endl; return 1; } if (info->requires_install && !gConfig().is_agent_installed()) { std::cerr << "Dropshell agent not installed for command: " << ctx.command << std::endl; std::cerr << "Please run 'dropshell install' to install the local dropshell agent." << std::endl; return 1; } int arg_count = ctx.args.size(); if (arg_count < info->min_args || (info->max_args != -1 && arg_count > info->max_args)) { std::cerr << "Invalid number of arguments for command: " << ctx.command << std::endl; std::cerr << "Usage: " << std::endl; std::cout << " "; print_left_aligned(info->help_usage,30); std::cout << info->help_description << std::endl; return 1; } return info->handler(ctx); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } } // ------------------------------------------------------------------------------------------------ struct ServerAndServices { std::string server_name; std::vector servicelist; }; bool getCLIServices(const std::string & arg2, const std::string & arg3, ServerAndServices & server_and_services) { if (arg2.empty()) return false; server_and_services.server_name = arg2; if (arg3.empty()) { server_and_services.servicelist = get_server_services_info(arg2); } else { server_and_services.servicelist.push_back(get_service_info(arg2, arg3)); } return true; } void printversion() { maketitle("DropShell version " + VERSION); std::cout << "Release date: " << RELEASE_DATE << std::endl; std::cout << "Author: " << AUTHOR << std::endl; std::cout << "License: " << LICENSE << std::endl; } auto command_match = [](const std::string& cmd_list, int argc, char* argv[]) -> bool { std::istringstream iss(cmd_list); std::string cmd_item; while (iss >> cmd_item) { if (cmd_item == safearg(argc, argv, 1)) { return true; } } return false; }; #define BOOLEXIT(CMD_LIST, RUNCMD) { \ if (command_match(CMD_LIST, argc, argv)) { \ return (RUNCMD) ? 0 : 1; \ } \ } #define HAPPYEXIT(CMD_LIST, RUNCMD) { \ if (command_match(CMD_LIST, argc, argv)) { \ RUNCMD; \ return 0; \ } \ } int old_main(int argc, char* argv[]) { HAPPYEXIT("hash", hash_demo_raw(safearg(argc,argv,2))) HAPPYEXIT("version", printversion()) BOOLEXIT("test-template", gTemplateManager().test_template(safearg(argc,argv,2))) ASSERT(safearg(argc,argv,1) != "assert", "Hello! Here is an assert."); try { // silently attempt to load the config file and templates. gConfig().load_config(); if (gConfig().is_config_set()) gTemplateManager().load_sources(); std::string cmd = argv[1]; // ------------------------------------------------------------ // from here we require the config file to be loaded. if (!gConfig().is_config_set()) return die("Please run 'dropshell edit' to set up the dropshell configuration."); const std::vector & server_definition_paths = gConfig().get_local_server_definition_paths(); if (server_definition_paths.size()>1) { // only show if there are multiple. std::cout << "Server definition paths: "; for (auto & dir : server_definition_paths) std::cout << "["<< dir << "] "; std::cout << std::endl; } if (gTemplateManager().is_loaded() && gTemplateManager().get_source_count() > 0) gTemplateManager().print_sources(); HAPPYEXIT("templates", gTemplateManager().list_templates()); if (cmd == "create-template") { if (argc < 3) return die("Error: create-template requires a template name"); return (gTemplateManager().create_template(argv[2])) ? 0 : 1; } if (cmd == "create-server") { if (argc < 3) return die("Error: create-server requires a server name"); return (create_server(argv[2])) ? 0 : 1; } if (cmd == "create-service") { if (argc < 5) return die("Error: not enough arguments.\ndropshell create-service server template service"); return (create_service(argv[2], argv[3], argv[4])) ? 0 : 1; } if (cmd == "ssh" && argc < 4) { if (argc < 3) return die("Error: ssh requires a server name and optionally service name"); service_runner::interactive_ssh(argv[2], "bash"); return 0; } // handle running a command. std::set commands; get_all_used_commands(commands); autocomplete::merge_commands(commands, autocomplete::service_commands_require_config); // handled by service_runner, but not in template_shell_commands. if (commands.count(cmd)) { std::set safe_commands = {"nuke", "fullnuke"}; if (safe_commands.count(cmd) && argc < 4) return die("Error: "+cmd+" requires a server name and service name. For safety, can't run on all services."); // get all the services to run the command on. ServerAndServices server_and_services; if (!getCLIServices(safearg(argc, argv, 2), safearg(argc, argv, 3), server_and_services)) return die("Error: "+cmd+" command requires server name and optionally service name"); // run the command on each service. for (const auto& service_info : server_and_services.servicelist) { if (!SIvalid(service_info)) std::cerr<<"Error: Unable to get service information."< additional_args; for (int i=4; i