diff --git a/src/commands/edit.cpp b/src/commands/edit.cpp index 2df6c2e..ac3dd07 100644 --- a/src/commands/edit.cpp +++ b/src/commands/edit.cpp @@ -50,7 +50,7 @@ struct EditCommandRegister { // ------------------------------------------------------------------------------------------------ // utility function to edit a file // ------------------------------------------------------------------------------------------------ -bool edit_file(const std::string &file_path) +bool edit_file(const std::string &file_path, bool has_bb64) { // make sure parent directory exists. std::string parent_dir = get_parent(file_path); @@ -72,7 +72,15 @@ bool edit_file(const std::string &file_path) } std::cout << "Editing file: " << file_path << std::endl; - return execute_local_command(editor_cmd, nullptr, cMode::Interactive); + + if (has_bb64) { + return execute_local_command(editor_cmd, nullptr, cMode::Interactive); + } + else { + // might not have bb64 at this early stage. Direct edit. + int ret = system(editor_cmd.c_str()); + return EXITSTATUSCHECK(ret); + } } // ------------------------------------------------------------------------------------------------ @@ -84,7 +92,7 @@ int edit_config() gConfig().save_config(false); // save defaults. std::string config_file = localfile::dropshell_json(); - if (!edit_file(config_file) || !std::filesystem::exists(config_file)) + if (!edit_file(config_file, false) || !std::filesystem::exists(config_file)) return die("Error: Failed to edit config file."); gConfig().load_config(); @@ -92,6 +100,9 @@ int edit_config() return die("Error: Failed to load and parse edited config file!"); gConfig().save_config(true); + + // make sure we have executables. + std::cout << "Successfully edited config file at " << config_file << std::endl; return 0; } @@ -113,7 +124,7 @@ int edit_server(const std::string &server_name) << "Once moved, reinstall all services with: dropshell install " << server_name; std::string config_file = serverpath + "/server.env"; - if (!edit_file(config_file)) { + if (!edit_file(config_file, true)) { std::cerr << "Error: Failed to edit server.env" << std::endl; std::cerr << "You can manually edit this file at: " << config_file << std::endl; std::cerr << "After editing, " << aftertext.str() << std::endl; @@ -135,7 +146,7 @@ int edit_service_config(const std::string &server, const std::string &service) return 1; } - if (edit_file(config_file) && std::filesystem::exists(config_file)) + if (edit_file(config_file, true) && std::filesystem::exists(config_file)) std::cout << "To apply your changes, run:\n dropshell install " + server + " " + service << std::endl; return 0; } diff --git a/src/commands/install.cpp b/src/commands/install.cpp index 7fd0c71..4636792 100644 --- a/src/commands/install.cpp +++ b/src/commands/install.cpp @@ -88,7 +88,7 @@ bool install_service(const std::string& server, const std::string& service, bool // Create service directory std::string remote_service_path = remotepath::service(server, service); std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path); - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), mkdir_cmd, {}), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("", mkdir_cmd, {}), cMode::Silent)) { std::cerr << "Failed to create service directory " << remote_service_path << std::endl; return false; @@ -96,7 +96,7 @@ bool install_service(const std::string& server, const std::string& service, bool // Check if rsync is installed on remote host std::string check_rsync_cmd = "which rsync"; - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), check_rsync_cmd, {}), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("", check_rsync_cmd, {}), cMode::Silent)) { std::cerr << "rsync is not installed on the remote host" << std::endl; return false; diff --git a/src/config.cpp b/src/config.cpp index 627b297..2f4842b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -5,7 +5,7 @@ #include "utils/utils.hpp" #include "utils/json.hpp" #include - +#include "utils/execute.hpp" namespace dropshell { @@ -85,7 +85,8 @@ bool config::save_config(bool create_aux_directories) std::vector paths = { get_local_template_cache_path(), get_local_backup_path(), - get_local_tempfiles_path() + get_local_tempfiles_path(), + get_local_executables_path() }; for (auto & p : get_local_server_definition_paths()) paths.push_back(p); @@ -98,6 +99,17 @@ bool config::save_config(bool create_aux_directories) } } + // also make sure the executables are in the path. + std::string executables_path = get_local_executables_path(); + + // download bb64. + std::string cmd = "cd " + executables_path + " && curl -fsSL -o bb64 https://gitea.jde.nz/public/bb64/releases/download/latest/bb64.amd64 && chmod a+x bb64"; + int ret = system(cmd.c_str()); + if (EXITSTATUSCHECK(ret)) + std::cout << "Downloaded bb64 to " << executables_path << std::endl; + else + std::cerr << "Failed to download bb64 to " << executables_path << std::endl; + return true; } diff --git a/src/main.cpp b/src/main.cpp index 3f23907..dc6a214 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -141,8 +141,6 @@ auto command_match = [](const std::string& cmd_list, int argc, char* argv[]) -> } - - int old_main(int argc, char* argv[]) { HAPPYEXIT("hash", hash_demo_raw(safearg(argc,argv,2))) HAPPYEXIT("version", printversion()) diff --git a/src/server_env_manager.cpp b/src/server_env_manager.cpp index b5f83da..bf066ed 100644 --- a/src/server_env_manager.cpp +++ b/src/server_env_manager.cpp @@ -122,7 +122,6 @@ std::optional server_env_manager::construct_standard_template_run_cmd( sCommand sc( remote_service_template_path, - remotepath::executables(mServerName), quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars ); @@ -137,12 +136,12 @@ std::optional server_env_manager::construct_standard_template_run_cmd( bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const { - sCommand scommand("",remotepath::executables(mServerName),"test -d " + quote(dir_path),{}); + sCommand scommand("", "test -d " + quote(dir_path),{}); return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); } bool server_env_manager::check_remote_file_exists(const std::string& file_path) const { - sCommand scommand("",remotepath::executables(mServerName),"test -f " + quote(file_path),{}); + sCommand scommand("", "test -f " + quote(file_path),{}); return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); } @@ -156,7 +155,7 @@ bool server_env_manager::check_remote_items_exist(const std::vector file_names_str += std::filesystem::path(file_path).filename().string() + " "; } // check if all items in the vector exist on the remote server, in a single command. - sCommand scommand("",remotepath::executables(mServerName),"for item in " + file_paths_str + "; do test -f $item; done",{}); + sCommand scommand("", "for item in " + file_paths_str + "; do test -f $item; done",{}); bool okay = execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); if (!okay) { @@ -187,7 +186,7 @@ bool server_env_manager::remove_remote_dir(const std::string &dir_path, bool sil if (!silent) std::cout << "Running command: " << remote_cmd << std::endl; - sCommand scommand("",remotepath::executables(mServerName),remote_cmd,{}); + sCommand scommand("", remote_cmd,{}); cMode mode = (silent ? cMode::Silent : cMode::None); return execute_ssh_command(get_SSH_INFO(), scommand, mode); diff --git a/src/server_env_manager.hpp b/src/server_env_manager.hpp index b1e9223..bd4a0d9 100644 --- a/src/server_env_manager.hpp +++ b/src/server_env_manager.hpp @@ -43,7 +43,7 @@ class server_env_manager { std::string get_SSH_USER() const { return get_variable("SSH_USER"); } std::string get_SSH_PORT() const { return get_variable("SSH_PORT"); } std::string get_DROPSHELL_DIR() const { return get_variable("DROPSHELL_DIR"); } - sSSHInfo get_SSH_INFO() const { return sSSHInfo{get_SSH_HOST(), get_SSH_USER(), get_SSH_PORT()}; } + sSSHInfo get_SSH_INFO() const { return sSSHInfo{get_SSH_HOST(), get_SSH_USER(), get_SSH_PORT(), get_server_name()}; } bool is_valid() const { return mValid; } std::string get_server_name() const { return mServerName; } diff --git a/src/service_runner.cpp b/src/service_runner.cpp index 00d1d92..e0f7cae 100644 --- a/src/service_runner.cpp +++ b/src/service_runner.cpp @@ -241,7 +241,7 @@ bool service_runner::interactive_ssh(const std::string & server_name, const std: std::cerr << "Error: Invalid server environment file: " << server_name << std::endl; return false; } - sCommand scommand("",remotepath::executables(server_name), "bash",{}); + sCommand scommand("", "bash",{}); return execute_ssh_command(env.get_SSH_INFO(), scommand, cMode::Interactive); } @@ -426,7 +426,7 @@ bool service_runner::backup(bool silent) { std::string remote_backups_dir = remotepath::backups(mServer); if (!silent) std::cout << "Remote backups directory on "<< mServer <<": " << remote_backups_dir << std::endl; std::string mkdir_cmd = "mkdir -p " + quote(remote_backups_dir); - if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServer), mkdir_cmd, {}), cMode::Silent)) { + if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",mkdir_cmd, {}), cMode::Silent)) { std::cerr << "Failed to create backups directory on server" << std::endl; return false; } @@ -484,7 +484,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe { std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10); std::string mkdir_cmd = "mkdir -p " + quote(p); - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server_env.get_server_name()), mkdir_cmd, {}), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("", mkdir_cmd, {}), cMode::Silent)) std::cerr << "Failed to create temp directory on server" << std::endl; else mPath = p; @@ -493,7 +493,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe cRemoteTempFolder::~cRemoteTempFolder() { std::string rm_cmd = "rm -rf " + quote(mPath); - execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServerEnv.get_server_name()), rm_cmd, {}), cMode::Silent); + execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("", rm_cmd, {}), cMode::Silent); } std::string cRemoteTempFolder::path() const diff --git a/src/utils/execute.cpp b/src/utils/execute.cpp index 17e71a3..a8eb448 100644 --- a/src/utils/execute.cpp +++ b/src/utils/execute.cpp @@ -12,19 +12,20 @@ #include "utils/utils.hpp" #include "utils/b64ed.hpp" #include "config.hpp" - -bool EXITSTATUSCHECK(int ret) -{ - return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute. -} +#include "utils/directories.hpp" namespace dropshell { + bool EXITSTATUSCHECK(int ret) + { + return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute. + } + bool execute_local_command_interactive(const sCommand &command) { if (command.get_command_to_run().empty()) return false; - std::string full_command = command.construct_cmd(); // Get the command string + std::string full_command = command.construct_cmd(gConfig().get_local_executables_path()); // Get the command string pid_t pid = fork(); @@ -55,7 +56,7 @@ namespace dropshell ASSERT(output != nullptr, "Output string must be provided"); if (command.get_command_to_run().empty()) return false; - std::string full_cmd = command.construct_cmd() + " 2>&1"; + std::string full_cmd = command.construct_cmd(gConfig().get_local_executables_path()) + " 2>&1"; FILE *pipe = popen(full_cmd.c_str(), "r"); if (!pipe) { @@ -72,12 +73,12 @@ namespace dropshell bool execute_local_command(std::string command, std::string *output, cMode mode) { - return execute_local_command("",command,{}, output, mode); + return execute_local_command("", command, {}, output, mode); } bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map &env_vars, std::string *output, cMode mode) { - sCommand command(directory_to_run_in, gConfig().get_local_executables_path(), command_to_run, env_vars); + sCommand command(directory_to_run_in, command_to_run, env_vars); if (hasFlag(mode, cMode::Interactive)) { @@ -98,7 +99,7 @@ namespace dropshell if (command.get_command_to_run().empty()) return false; bool silent = hasFlag(mode, cMode::Silent); - std::string full_cmd = command.construct_cmd() + " 2>&1" + (silent ? " > /dev/null" : ""); + std::string full_cmd = command.construct_cmd(gConfig().get_local_executables_path()) + " 2>&1" + (silent ? " > /dev/null" : ""); int ret = system(full_cmd.c_str()); bool ok = EXITSTATUSCHECK(ret); @@ -121,36 +122,38 @@ namespace dropshell ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "") << ssh_info.user << "@" << ssh_info.host; + std::string remote_executables_path = remotepath::executables(ssh_info.server_ID); + bool rval = execute_local_command( - "", // directory to run in - ssh_cmd.str() + " " + remote_command.construct_cmd(), // local command to run - {}, // environment variables - output, // output string - mode // mode - ); + "", // directory to run in + ssh_cmd.str() + " " + remote_command.construct_cmd(remote_executables_path), // local command to run + {}, // environment variables + output, // output string + mode // mode + ); if (!rval && !hasFlag(mode, cMode::Silent)) { std::cerr << std::endl << std::endl; std::cerr << "Error: Failed to execute ssh command:" << std::endl; - std::cerr << "\033[90m" << ssh_cmd.str() + " " + remote_command.construct_cmd() << "\033[0m" << std::endl; + std::cerr << "\033[90m" << ssh_cmd.str() + " " + remote_command.construct_cmd(remote_executables_path) << "\033[0m" << std::endl; std::cerr << std::endl << std::endl; } return rval; } - std::string sCommand::makesafecmd(const std::string &command) const + std::string sCommand::makesafecmd(std::string executables_path, const std::string &command) const { if (command.empty()) return ""; std::string encoded = base64_encode(dequote(trim(command))); - std::string commandstr = mExecutablesPath + "/bb64 " + encoded; + std::string commandstr = executables_path + "/bb64 " + encoded; return commandstr; } - std::string sCommand::construct_cmd() const + std::string sCommand::construct_cmd(std::string executables_path) const { if (mCmd.empty()) return ""; @@ -167,7 +170,7 @@ namespace dropshell cmdstr += mCmd; - cmdstr = makesafecmd(cmdstr); + cmdstr = makesafecmd(executables_path, cmdstr); return cmdstr; } diff --git a/src/utils/execute.hpp b/src/utils/execute.hpp index 2d2c3ee..5f9baee 100644 --- a/src/utils/execute.hpp +++ b/src/utils/execute.hpp @@ -28,6 +28,7 @@ typedef struct sSSHInfo { std::string host; std::string user; std::string port; + std::string server_ID; // dropshell name for server. } sSSHInfo; bool execute_local_command(std::string command, std::string * output = nullptr, cMode mode = cMode::None); @@ -41,11 +42,10 @@ bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & remote_comm // class to hold a command to run on the remote server. class sCommand { public: - sCommand(std::string directory_to_run_in, std::string executables_path, std::string command_to_run, const std::map & env_vars) : - mDir(directory_to_run_in), mExecutablesPath(executables_path), mCmd(command_to_run), mVars(env_vars) {} + sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map & env_vars) : + mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars) {} std::string get_directory_to_run_in() const { return mDir; } - std::string get_executables_path() const { return mExecutablesPath; } std::string get_command_to_run() const { return mCmd; } const std::map& get_env_vars() const { return mVars; } @@ -53,18 +53,20 @@ class sCommand { bool empty() const { return mCmd.empty(); } - std::string construct_cmd() const; + std::string construct_cmd(std::string executables_path) const; private: - std::string makesafecmd(const std::string& command) const; + std::string makesafecmd(std::string executables_path, const std::string& command) const; private: std::string mDir; - std::string mExecutablesPath; std::string mCmd; std::map mVars; }; +bool EXITSTATUSCHECK(int ret); + + } // namespace dropshell