This commit is contained in:
parent
547482edc6
commit
61218f8866
@ -32,6 +32,9 @@ configure_file(
|
|||||||
# Set CMAKE_MODULE_PATH to include our custom find modules
|
# Set CMAKE_MODULE_PATH to include our custom find modules
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
# Find required libraries
|
||||||
|
find_package(LibSSH REQUIRED)
|
||||||
|
|
||||||
# Auto-detect source files
|
# Auto-detect source files
|
||||||
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
file(GLOB_RECURSE HEADERS "src/*.hpp")
|
file(GLOB_RECURSE HEADERS "src/*.hpp")
|
||||||
@ -45,6 +48,7 @@ target_include_directories(dropshell PRIVATE
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utils
|
${CMAKE_CURRENT_SOURCE_DIR}/src/utils
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/contrib
|
${CMAKE_CURRENT_SOURCE_DIR}/src/contrib
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/src>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/src>
|
||||||
|
${LIBSSH_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
@ -54,7 +58,7 @@ FetchContent_Declare(
|
|||||||
GIT_TAG v2.1.5 # <HASH or TAG>
|
GIT_TAG v2.1.5 # <HASH or TAG>
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(libassert)
|
FetchContent_MakeAvailable(libassert)
|
||||||
target_link_libraries(dropshell libassert::assert)
|
target_link_libraries(dropshell PRIVATE libassert::assert)
|
||||||
|
|
||||||
# On windows copy libassert.dll to the same directory as the executable for your_target
|
# On windows copy libassert.dll to the same directory as the executable for your_target
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@ -68,6 +72,7 @@ endif()
|
|||||||
|
|
||||||
# Link libraries
|
# Link libraries
|
||||||
target_link_libraries(dropshell PRIVATE
|
target_link_libraries(dropshell PRIVATE
|
||||||
|
${LIBSSH_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install targets
|
# Install targets
|
||||||
|
35
cmake/FindLibSSH.cmake
Normal file
35
cmake/FindLibSSH.cmake
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# - Try to find LibSSH
|
||||||
|
# Once done this will define
|
||||||
|
# LIBSSH_FOUND - System has LibSSH
|
||||||
|
# LIBSSH_INCLUDE_DIRS - The LibSSH include directories
|
||||||
|
# LIBSSH_LIBRARIES - The libraries needed to use LibSSH
|
||||||
|
# LIBSSH_DEFINITIONS - Compiler switches required for using LibSSH
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if(PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(PC_LIBSSH QUIET libssh)
|
||||||
|
set(LIBSSH_DEFINITIONS ${PC_LIBSSH_CFLAGS_OTHER})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_path(LIBSSH_INCLUDE_DIR
|
||||||
|
NAMES libssh/libssh.h
|
||||||
|
HINTS ${PC_LIBSSH_INCLUDEDIR} ${PC_LIBSSH_INCLUDE_DIRS}
|
||||||
|
PATH_SUFFIXES libssh
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(LIBSSH_LIBRARY
|
||||||
|
NAMES ssh libssh
|
||||||
|
HINTS ${PC_LIBSSH_LIBDIR} ${PC_LIBSSH_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# Handle the QUIETLY and REQUIRED arguments and set LIBSSH_FOUND to TRUE
|
||||||
|
# if all listed variables are TRUE
|
||||||
|
find_package_handle_standard_args(LibSSH DEFAULT_MSG
|
||||||
|
LIBSSH_LIBRARY LIBSSH_INCLUDE_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
mark_as_advanced(LIBSSH_INCLUDE_DIR LIBSSH_LIBRARY)
|
||||||
|
|
||||||
|
set(LIBSSH_LIBRARIES ${LIBSSH_LIBRARY})
|
||||||
|
set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR})
|
@ -66,6 +66,9 @@ bool service_runner::install(bool silent) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure all shell files are executable
|
||||||
|
make_shell_files_executable(tinfo.local_template_path().string());
|
||||||
|
|
||||||
// Copy template files
|
// Copy template files
|
||||||
{
|
{
|
||||||
if (!rsync_copy(tinfo.local_template_path().string()+"/", remotepath::service_template(mServer, mService)+"/", silent)) {
|
if (!rsync_copy(tinfo.local_template_path().string()+"/", remotepath::service_template(mServer, mService)+"/", silent)) {
|
||||||
@ -387,7 +390,7 @@ bool service_runner::interactive_ssh(const std::string & server_name, const std:
|
|||||||
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return 0==runner::execute_cmd("bash",{}, "", {}, false, true, env.get_SSH_INFO());
|
return 0==runner::execute_cmd("", {}, "", {}, false, true, env.get_SSH_INFO());
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_runner::edit_server(const std::string &server_name)
|
void service_runner::edit_server(const std::string &server_name)
|
||||||
|
@ -118,36 +118,56 @@ std::string ssh_build_command_only(const std::string& command, const std::vector
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, const std::string& command, std::string* output) {
|
int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, const std::string& command, std::string* output) {
|
||||||
|
// Request a PTY with xterm-256color type for color support
|
||||||
|
// First try using default terminal settings - should work with libssh 0.9.0+
|
||||||
int rc = ssh_channel_request_pty(channel);
|
int rc = ssh_channel_request_pty(channel);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
if (output) *output = std::string("Failed to request pty: ") + ssh_get_error(session);
|
if (output) *output = std::string("Failed to request pty: ") + ssh_get_error(session);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to explicitly tell the server we want colors through additional means
|
||||||
|
// 1. Set TERM environment variable
|
||||||
|
rc = ssh_channel_request_env(channel, "TERM", "xterm-256color");
|
||||||
|
// Ignore errors - this is optional
|
||||||
|
|
||||||
|
// 2. Request a shell
|
||||||
rc = ssh_channel_request_shell(channel);
|
rc = ssh_channel_request_shell(channel);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
if (output) *output = std::string("Failed to request shell: ") + ssh_get_error(session);
|
if (output) *output = std::string("Failed to request shell: ") + ssh_get_error(session);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct termios orig_termios, raw_termios;
|
struct termios orig_termios, raw_termios;
|
||||||
tcgetattr(STDIN_FILENO, &orig_termios);
|
tcgetattr(STDIN_FILENO, &orig_termios);
|
||||||
raw_termios = orig_termios;
|
raw_termios = orig_termios;
|
||||||
cfmakeraw(&raw_termios);
|
cfmakeraw(&raw_termios);
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &raw_termios);
|
tcsetattr(STDIN_FILENO, TCSANOW, &raw_termios);
|
||||||
|
|
||||||
if (!command.empty()) {
|
if (!command.empty()) {
|
||||||
ssh_channel_write(channel, remote_cmd_str.c_str(), remote_cmd_str.size());
|
ssh_channel_write(channel, remote_cmd_str.c_str(), remote_cmd_str.size());
|
||||||
ssh_channel_write(channel, "\n", 1);
|
ssh_channel_write(channel, "\n", 1);
|
||||||
|
} else {
|
||||||
|
// Initialize bash with color support if no specific command
|
||||||
|
std::string init_cmd = "export TERM=xterm-256color && if [ -f ~/.bashrc ]; then source ~/.bashrc; fi";
|
||||||
|
ssh_channel_write(channel, init_cmd.c_str(), init_cmd.size());
|
||||||
|
ssh_channel_write(channel, "\n", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxfd = STDIN_FILENO > STDOUT_FILENO ? STDIN_FILENO : STDOUT_FILENO;
|
int maxfd = STDIN_FILENO > STDOUT_FILENO ? STDIN_FILENO : STDOUT_FILENO;
|
||||||
maxfd = maxfd > ssh_get_fd(session) ? maxfd : ssh_get_fd(session);
|
maxfd = maxfd > ssh_get_fd(session) ? maxfd : ssh_get_fd(session);
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
fd_set fds_read;
|
fd_set fds_read;
|
||||||
FD_ZERO(&fds_read);
|
FD_ZERO(&fds_read);
|
||||||
FD_SET(STDIN_FILENO, &fds_read);
|
FD_SET(STDIN_FILENO, &fds_read);
|
||||||
FD_SET(ssh_get_fd(session), &fds_read);
|
FD_SET(ssh_get_fd(session), &fds_read);
|
||||||
|
|
||||||
int ret = select(maxfd + 1, &fds_read, nullptr, nullptr, nullptr);
|
int ret = select(maxfd + 1, &fds_read, nullptr, nullptr, nullptr);
|
||||||
if (ret < 0) break;
|
if (ret < 0) break;
|
||||||
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &fds_read)) {
|
if (FD_ISSET(STDIN_FILENO, &fds_read)) {
|
||||||
ssize_t n = read(STDIN_FILENO, buffer, sizeof(buffer));
|
ssize_t n = read(STDIN_FILENO, buffer, sizeof(buffer));
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
@ -157,6 +177,7 @@ int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, cons
|
|||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(ssh_get_fd(session), &fds_read)) {
|
if (FD_ISSET(ssh_get_fd(session), &fds_read)) {
|
||||||
int n = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
int n = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
@ -165,10 +186,12 @@ int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, cons
|
|||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_channel_is_closed(channel) || ssh_channel_is_eof(channel)) {
|
if (ssh_channel_is_closed(channel) || ssh_channel_is_eof(channel)) {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ int execute_cmd(
|
|||||||
const std::map<std::string, std::string>& env,
|
const std::map<std::string, std::string>& env,
|
||||||
const bool silent,
|
const bool silent,
|
||||||
const bool interactive,
|
const bool interactive,
|
||||||
const copySSHPtr sshinfo = nullptr,
|
const copySSHPtr& sshinfo = nullptr,
|
||||||
std::string* output = nullptr
|
std::string* output = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -312,6 +312,32 @@ std::string random_alphanumeric_string(int length)
|
|||||||
return random_string;
|
return random_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void make_shell_files_executable(const std::string &dir_path)
|
||||||
|
{ // recursively make all shell files in the directory executable
|
||||||
|
|
||||||
|
const auto desired_perms = std::filesystem::perms::owner_read | std::filesystem::perms::owner_exec |
|
||||||
|
std::filesystem::perms::group_read | std::filesystem::perms::group_exec |
|
||||||
|
std::filesystem::perms::others_read | std::filesystem::perms::others_exec;
|
||||||
|
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(dir_path)) {
|
||||||
|
if (entry.path().extension() == ".sh") {
|
||||||
|
// check if permissions are already set
|
||||||
|
auto currentperms = std::filesystem::status(entry.path()).permissions();
|
||||||
|
if ((currentperms & desired_perms) == desired_perms) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set permissions
|
||||||
|
std::cout << "Setting executable permissions for " << entry.path() << std::endl;
|
||||||
|
|
||||||
|
std::filesystem::permissions(entry.path(), desired_perms, std::filesystem::perm_options::add);
|
||||||
|
}
|
||||||
|
else if (std::filesystem::is_directory(entry.path())) {
|
||||||
|
make_shell_files_executable(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string requote(std::string str) {
|
std::string requote(std::string str) {
|
||||||
return quote(trim(dequote(trim(str))));
|
return quote(trim(dequote(trim(str))));
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,6 @@ std::string replace_with_environment_variables_like_bash(std::string str);
|
|||||||
|
|
||||||
std::string random_alphanumeric_string(int length);
|
std::string random_alphanumeric_string(int length);
|
||||||
|
|
||||||
|
void make_shell_files_executable(const std::string& dir_path);
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
0
templates/dropshell-agent/_nuke_other.sh
Normal file → Executable file
0
templates/dropshell-agent/_nuke_other.sh
Normal file → Executable file
0
templates/dropshell-agent/install.sh
Normal file → Executable file
0
templates/dropshell-agent/install.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_allservicesstatus.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_allservicesstatus.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_autocommands.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_autocommands.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_common.sh
Normal file → Executable file
0
templates/dropshell-agent/shared/_common.sh
Normal file → Executable file
0
templates/dropshell-agent/uninstall.sh
Normal file → Executable file
0
templates/dropshell-agent/uninstall.sh
Normal file → Executable file
0
templates/squashkiwi/backup.sh
Normal file → Executable file
0
templates/squashkiwi/backup.sh
Normal file → Executable file
0
templates/squashkiwi/install.sh
Normal file → Executable file
0
templates/squashkiwi/install.sh
Normal file → Executable file
0
templates/squashkiwi/logs.sh
Normal file → Executable file
0
templates/squashkiwi/logs.sh
Normal file → Executable file
0
templates/squashkiwi/nuke.sh
Normal file → Executable file
0
templates/squashkiwi/nuke.sh
Normal file → Executable file
0
templates/squashkiwi/ports.sh
Normal file → Executable file
0
templates/squashkiwi/ports.sh
Normal file → Executable file
0
templates/squashkiwi/restore.sh
Normal file → Executable file
0
templates/squashkiwi/restore.sh
Normal file → Executable file
0
templates/squashkiwi/ssh.sh
Normal file → Executable file
0
templates/squashkiwi/ssh.sh
Normal file → Executable file
0
templates/squashkiwi/start.sh
Normal file → Executable file
0
templates/squashkiwi/start.sh
Normal file → Executable file
0
templates/squashkiwi/status.sh
Normal file → Executable file
0
templates/squashkiwi/status.sh
Normal file → Executable file
0
templates/squashkiwi/stop.sh
Normal file → Executable file
0
templates/squashkiwi/stop.sh
Normal file → Executable file
0
templates/squashkiwi/uninstall.sh
Normal file → Executable file
0
templates/squashkiwi/uninstall.sh
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user