.
This commit is contained in:
parent
8c85fe8819
commit
10d663971c
59
.gitignore
vendored
Normal file
59
.gitignore
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
# Build directories
|
||||
build/
|
||||
cmake-build-*/
|
||||
out/
|
||||
bin/
|
||||
lib/
|
||||
|
||||
# Compiled Object files
|
||||
*.o
|
||||
*.obj
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
|
||||
# Executables
|
||||
dropshell
|
||||
|
||||
# CMake
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
*.cmake
|
||||
|
||||
# IDE specific files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs and databases
|
||||
*.log
|
||||
*.sqlite
|
||||
|
||||
# Local configuration
|
||||
*.local
|
||||
*.conf.local
|
||||
|
||||
# Dependencies
|
||||
deps/
|
||||
vendor/
|
36
CMakeLists.txt
Normal file
36
CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(dropshell VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Find required packages
|
||||
find_package(Boost REQUIRED COMPONENTS program_options filesystem system)
|
||||
|
||||
# Add executable
|
||||
add_executable(dropshell
|
||||
src/main.cpp
|
||||
src/version.cpp
|
||||
src/status.cpp
|
||||
src/servers.cpp
|
||||
src/help.cpp
|
||||
src/config.cpp
|
||||
)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(dropshell PRIVATE
|
||||
Boost::program_options
|
||||
Boost::filesystem
|
||||
Boost::system
|
||||
)
|
||||
|
||||
# Install targets
|
||||
install(TARGETS dropshell
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
# Install completion script
|
||||
install(FILES src/dropshell-completion.bash
|
||||
DESTINATION /etc/bash_completion.d
|
||||
RENAME dropshell
|
||||
)
|
84
README.md
84
README.md
@ -1,3 +1,83 @@
|
||||
# dropshell
|
||||
# Dropshell
|
||||
|
||||
Simple remote server management system, based on bash scripts, and works with anything.
|
||||
A system management tool for server operations, written in C++.
|
||||
|
||||
## Features
|
||||
|
||||
- System status monitoring
|
||||
- Server configuration management
|
||||
- Bash completion support
|
||||
- Command-line interface with help and version information
|
||||
|
||||
## Building from Source
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- CMake (>= 3.10)
|
||||
- Boost C++ Libraries (program_options, filesystem, system)
|
||||
- C++17 compatible compiler
|
||||
- Debian packaging tools (for creating packages)
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/j842/dropshell.git
|
||||
cd dropshell
|
||||
|
||||
# Create build directory
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
# Configure and build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
### Installing
|
||||
|
||||
#### From Source
|
||||
|
||||
```bash
|
||||
# Install from source build
|
||||
sudo make install
|
||||
```
|
||||
|
||||
#### From Debian Package
|
||||
|
||||
To create a Debian package:
|
||||
|
||||
```bash
|
||||
# Install build dependencies
|
||||
sudo apt-get install devscripts debhelper cmake libboost-all-dev
|
||||
|
||||
# Build the package
|
||||
dpkg-buildpackage -us -uc
|
||||
|
||||
# Install the package
|
||||
sudo dpkg -i ../dropshell_1.0.0-1_*.deb
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Show help
|
||||
dropshell help
|
||||
|
||||
# Show version
|
||||
dropshell version
|
||||
|
||||
# Check system status
|
||||
dropshell status
|
||||
|
||||
# List configured servers
|
||||
dropshell servers
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The configuration file is located at `/etc/dropshell.conf`. You can modify this file to change default settings.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details
|
80
build.sh
Executable file
80
build.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print status messages
|
||||
print_status() {
|
||||
echo -e "${GREEN}[*] $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[!] $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[!] $1${NC}"
|
||||
}
|
||||
|
||||
# Check if build directory exists, if not create it
|
||||
if [ ! -d "build" ]; then
|
||||
print_status "Creating build directory..."
|
||||
mkdir build
|
||||
fi
|
||||
|
||||
# Enter build directory
|
||||
cd build
|
||||
|
||||
# Check if CMake is installed
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
print_error "CMake is not installed. Please install CMake first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if make is installed
|
||||
if ! command -v make &> /dev/null; then
|
||||
print_error "Make is not installed. Please install Make first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configure with CMake
|
||||
print_status "Configuring with CMake..."
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
# Build the project
|
||||
print_status "Building project..."
|
||||
make -j$(nproc)
|
||||
|
||||
# Check if build was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
print_status "Build successful!"
|
||||
print_status "Binary location: $(pwd)/dropshell"
|
||||
else
|
||||
print_error "Build failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if user wants to install
|
||||
read -p "Do you want to install the program? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_status "Installing dropshell..."
|
||||
sudo make install
|
||||
if [ $? -eq 0 ]; then
|
||||
print_status "Installation successful!"
|
||||
else
|
||||
print_error "Installation failed!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Return to original directory
|
||||
cd ..
|
||||
|
||||
print_status "Build process completed!"
|
8
debian/changelog
vendored
Normal file
8
debian/changelog
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
dropshell (1.0.0-1) unstable; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
* Converted from bash script to C++ implementation
|
||||
* Added proper system status monitoring
|
||||
* Improved server management functionality
|
||||
|
||||
-- j842 <j842@example.com> Sun, 21 Apr 2025 12:00:00 +0000
|
15
debian/control
vendored
Normal file
15
debian/control
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
Source: dropshell
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: j842 <j842@example.com>
|
||||
Build-Depends: debhelper (>= 10), cmake, libboost-all-dev
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://github.com/j842/dropshell
|
||||
|
||||
Package: dropshell
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libboost-program-options1.74.0, libboost-filesystem1.74.0, libboost-system1.74.0
|
||||
Description: A system management tool for server operations
|
||||
dropshell is a command-line tool for managing and monitoring servers.
|
||||
It provides functionality for checking system status, managing server
|
||||
configurations, and performing common administrative tasks.
|
26
debian/copyright
vendored
Normal file
26
debian/copyright
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: dropshell
|
||||
Source: https://github.com/j842/dropshell
|
||||
|
||||
Files: *
|
||||
Copyright: 2025 j842
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
14
debian/rules
vendored
Normal file
14
debian/rules
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_auto_install
|
||||
# Install bash completion
|
||||
install -D -m 644 src/dropshell-completion.bash debian/dropshell/etc/bash_completion.d/dropshell
|
||||
# Install configuration
|
||||
install -D -m 644 src/dropshell.conf debian/dropshell/etc/dropshell.conf
|
137
install.sh
137
install.sh
@ -1,137 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
source "$SCRIPT_DIR/src/version.sh"
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to create directory with proper ownership
|
||||
mkdir_with_ownership() {
|
||||
local target_dir="$1"
|
||||
local parent_dir="$(dirname "$target_dir")"
|
||||
|
||||
# Find the lowest existing parent directory
|
||||
while [ ! -d "$parent_dir" ] && [ "$parent_dir" != "/" ]; do
|
||||
parent_dir="$(dirname "$parent_dir")"
|
||||
done
|
||||
|
||||
# If we found an existing directory, get its ownership
|
||||
if [ -d "$parent_dir" ]; then
|
||||
local owner=$(stat -c %U "$parent_dir")
|
||||
local group=$(stat -c %G "$parent_dir")
|
||||
install -d -o "$owner" -g "$group" "$target_dir"
|
||||
else
|
||||
echo -e "${RED}Error: Could not find any existing parent directory${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if USER_DEFINITIONS is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${RED}Error: USER_DEFINITIONS path is required${NC}"
|
||||
echo "Usage: $0 <USER_DEFINITIONS_PATH>"
|
||||
echo "Example: $0 ~/.config/dropshell"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
USER_DEFINITIONS="$1"
|
||||
|
||||
# Script locations
|
||||
SCRIPT_SOURCE="$SCRIPT_DIR/src/dropshell.sh"
|
||||
SCRIPT_DEST="/usr/local/bin/dropshell"
|
||||
COMPLETION_SOURCE="$SCRIPT_DIR/src/dropshell-completion.bash"
|
||||
COMPLETION_DEST="/etc/bash_completion.d/dropshell"
|
||||
EXAMPLE_DIR="$SCRIPT_DIR/.example"
|
||||
DROPSHELL_OPT="/opt/dropshell"
|
||||
|
||||
# Check if running with sudo/root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}Please run as root or with sudo${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if source script exists
|
||||
if [ ! -f "$SCRIPT_SOURCE" ]; then
|
||||
echo -e "${RED}Error: $SCRIPT_SOURCE not found${NC}"
|
||||
echo "Please ensure the script exists in the src directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if completion script exists
|
||||
if [ ! -f "$COMPLETION_SOURCE" ]; then
|
||||
echo -e "${RED}Error: $COMPLETION_SOURCE not found${NC}"
|
||||
echo "Please ensure the completion script exists in the src directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create user definitions directory if it doesn't exist
|
||||
if [ ! -d "$USER_DEFINITIONS" ]; then
|
||||
echo "Creating user definitions directory..."
|
||||
mkdir_with_ownership "$USER_DEFINITIONS" || exit 1
|
||||
fi
|
||||
|
||||
# Check if example directory exists and copy example files if needed
|
||||
if [ ! -d "$EXAMPLE_DIR" ]; then
|
||||
echo -e "${RED}Error: Example directory not found at $EXAMPLE_DIR${NC}"
|
||||
echo "Please ensure the .example directory exists in the project root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check and create servers directory
|
||||
if [ ! -d "$USER_DEFINITIONS/servers" ]; then
|
||||
echo "Copying example files..."
|
||||
mkdir_with_ownership "$USER_DEFINITIONS/servers" || exit 1
|
||||
cp -ra "$EXAMPLE_DIR"/servers/* "$USER_DEFINITIONS/servers"
|
||||
fi
|
||||
|
||||
# Check and create usertemplates directory
|
||||
if [ ! -d "$USER_DEFINITIONS/usertemplates" ]; then
|
||||
echo "Copying example files..."
|
||||
mkdir_with_ownership "$USER_DEFINITIONS/usertemplates" || exit 1
|
||||
cp -ra "$EXAMPLE_DIR"/usertemplates/* "$USER_DEFINITIONS/usertemplates"
|
||||
fi
|
||||
|
||||
# install user directory.
|
||||
echo "Creating symbolic link for /opt/dropshell/user..."
|
||||
mkdir -p "$DROPSHELL_OPT" || exit 1
|
||||
if [ -e "$DROPSHELL_OPT/user" ]; then
|
||||
rm -rf "$DROPSHELL_OPT/user"
|
||||
fi
|
||||
ln -s "$USER_DEFINITIONS" "$DROPSHELL_OPT/user"
|
||||
|
||||
# Create symbolic link
|
||||
echo "Creating symbolic link for running from $SCRIPT_DEST..."
|
||||
if [ -L "$SCRIPT_DEST" ]; then
|
||||
rm "$SCRIPT_DEST"
|
||||
fi
|
||||
ln -s "$SCRIPT_SOURCE" "$SCRIPT_DEST"
|
||||
|
||||
# Make sure the scripts are executable
|
||||
chmod +x "$SCRIPT_SOURCE"
|
||||
chmod +x "$COMPLETION_SOURCE"
|
||||
|
||||
# Install bash completion
|
||||
echo "Installing bash completion..."
|
||||
if [ ! -d "/etc/bash_completion.d" ]; then
|
||||
mkdir_with_ownership "/etc/bash_completion.d" || exit 1
|
||||
fi
|
||||
|
||||
# Install completion script
|
||||
cp "$COMPLETION_SOURCE" "$COMPLETION_DEST"
|
||||
chmod 644 "$COMPLETION_DEST"
|
||||
|
||||
# Create environment file
|
||||
cat > "/etc/dropshell.conf" << EOF
|
||||
# Dropshell configuration
|
||||
USER_DEFINITIONS="$USER_DEFINITIONS"
|
||||
EOF
|
||||
|
||||
# Source the completion script
|
||||
echo "source $COMPLETION_DEST" >> ~/.bashrc
|
||||
|
||||
echo -e "${GREEN}Installation completed successfully!${NC}"
|
||||
|
||||
exit 0
|
92
install_prerequisites.sh
Executable file
92
install_prerequisites.sh
Executable file
@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print status messages
|
||||
print_status() {
|
||||
echo -e "${GREEN}[*] $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[!] $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[!] $1${NC}"
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
print_error "Please run this script as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect distribution
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
OS=$NAME
|
||||
VER=$VERSION_ID
|
||||
else
|
||||
print_error "Could not detect distribution"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "Detected OS: $OS $VER"
|
||||
|
||||
# Define packages based on distribution
|
||||
case $OS in
|
||||
"Ubuntu"|"Debian GNU/Linux")
|
||||
# Common packages for both Ubuntu and Debian
|
||||
PACKAGES="cmake make g++ libboost-all-dev devscripts debhelper"
|
||||
;;
|
||||
*)
|
||||
print_error "Unsupported distribution: $OS"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Function to check if a package is installed
|
||||
is_package_installed() {
|
||||
dpkg -l "$1" 2>/dev/null | grep -q "^ii"
|
||||
}
|
||||
|
||||
# Install missing packages
|
||||
print_status "Checking and installing required packages..."
|
||||
for pkg in $PACKAGES; do
|
||||
if ! is_package_installed "$pkg"; then
|
||||
print_status "Installing $pkg..."
|
||||
apt-get install -y "$pkg"
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to install $pkg"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_status "$pkg is already installed"
|
||||
fi
|
||||
done
|
||||
|
||||
# Update package lists
|
||||
print_status "Updating package lists..."
|
||||
apt-get update
|
||||
|
||||
# Verify all required tools are installed
|
||||
print_status "Verifying installation..."
|
||||
for tool in cmake make g++; do
|
||||
if ! command -v "$tool" &> /dev/null; then
|
||||
print_error "$tool is not installed properly"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check Boost installation
|
||||
if [ ! -d "/usr/include/boost" ]; then
|
||||
print_error "Boost headers not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "All dependencies installed successfully!"
|
||||
print_status "You can now run ./build.sh to build the project"
|
124
src/config.cpp
Normal file
124
src/config.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
// Default user directory
|
||||
static std::string user_directory;
|
||||
static bool config_loaded = false;
|
||||
|
||||
bool is_config_loaded() {
|
||||
return config_loaded;
|
||||
}
|
||||
|
||||
bool get_config_path(std::string& path) {
|
||||
// Try ~/.config/dropshell/dropshell.conf
|
||||
const char* home = std::getenv("HOME");
|
||||
if (home) {
|
||||
fs::path user_path = fs::path(home) / ".config" / "dropshell" / "dropshell.conf";
|
||||
if (!fs::exists(user_path)) {
|
||||
// create path
|
||||
fs::create_directories(user_path.parent_path());
|
||||
}
|
||||
|
||||
path = user_path.string();
|
||||
return true;
|
||||
}
|
||||
std::cerr << "Warning: Couldn't determine user directory" << std::endl;
|
||||
path = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_user_directory(std::string& path) {
|
||||
path = user_directory;
|
||||
return !path.empty();
|
||||
}
|
||||
|
||||
bool load_config() {
|
||||
std::string config_path;
|
||||
if (!get_config_path(config_path))
|
||||
return true;
|
||||
|
||||
if (config_path.empty()) {
|
||||
// No config file found, but this is not an error
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
pt::ptree tree;
|
||||
pt::read_ini(config_path, tree);
|
||||
bool config_okay = true;
|
||||
|
||||
// Try to read user directory from config
|
||||
try {
|
||||
user_directory = tree.get<std::string>("user.directory");
|
||||
} catch (const pt::ptree_error&) {
|
||||
std::cerr << "Warning: User directory not set in config" << std::endl;
|
||||
config_okay = false; // Not a critical error
|
||||
}
|
||||
|
||||
// config loaded okay.
|
||||
config_loaded = config_okay;
|
||||
return true;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Warning: Error reading config file: " << e.what() << std::endl;
|
||||
return true; // Not a critical error
|
||||
}
|
||||
}
|
||||
|
||||
void init_user_directory(const std::string& path) {
|
||||
// Convert to absolute path
|
||||
fs::path abs_path = fs::absolute(path);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!fs::exists(abs_path)) {
|
||||
throw std::runtime_error("The user directory does not exist: " + abs_path.string());
|
||||
}
|
||||
|
||||
// Update config file
|
||||
std::string config_path;
|
||||
if (!get_config_path(config_path)) {
|
||||
// No config file exists, create one in user's home directory
|
||||
const char* home = std::getenv("HOME");
|
||||
if (!home) {
|
||||
throw std::runtime_error("HOME environment variable not set");
|
||||
}
|
||||
|
||||
fs::path config_dir = fs::path(home) / ".config" / "dropshell";
|
||||
if (!fs::exists(config_dir)) {
|
||||
fs::create_directories(config_dir);
|
||||
}
|
||||
config_path = (config_dir / "dropshell.conf").string();
|
||||
}
|
||||
|
||||
try {
|
||||
pt::ptree tree;
|
||||
// Read existing config if it exists
|
||||
if (fs::exists(config_path)) {
|
||||
pt::read_ini(config_path, tree);
|
||||
}
|
||||
|
||||
// Update user directory
|
||||
tree.put("user.directory", abs_path.string());
|
||||
|
||||
// Write back to config file
|
||||
pt::write_ini(config_path, tree);
|
||||
|
||||
// Update in-memory value
|
||||
user_directory = abs_path.string();
|
||||
|
||||
std::cout << "User directory initialized to: " << abs_path.string() << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
throw std::runtime_error("Failed to update config: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
@ -33,7 +33,6 @@ _dropshell_completions() {
|
||||
servers+=("$server_name")
|
||||
fi
|
||||
done
|
||||
|
||||
COMPREPLY=( $(compgen -W "${servers[@]}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
|
35
src/dropshell.hpp
Normal file
35
src/dropshell.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
// Version information
|
||||
const std::string VERSION = "1.0.0";
|
||||
const std::string RELEASE_DATE = "2025-04-21";
|
||||
const std::string AUTHOR = "j842";
|
||||
const std::string LICENSE = "MIT";
|
||||
|
||||
// Server information structure
|
||||
struct ServerInfo {
|
||||
std::string name;
|
||||
std::string address;
|
||||
};
|
||||
|
||||
// Command handlers
|
||||
void print_help(const boost::program_options::options_description& desc);
|
||||
void print_version();
|
||||
void check_status();
|
||||
void list_servers();
|
||||
void init_user_directory(const std::string& path);
|
||||
|
||||
// Utility functions
|
||||
std::vector<ServerInfo> get_configured_servers();
|
||||
bool get_config_path(std::string& path);
|
||||
bool load_config();
|
||||
bool is_config_loaded();
|
||||
bool get_user_directory(std::string& path);
|
||||
|
||||
} // namespace dropshell
|
125
src/dropshell.sh
125
src/dropshell.sh
@ -1,125 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script name: dropshell.sh
|
||||
# Description: A basic shell script for common operations
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Source version information
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
source "$SCRIPT_DIR/version.sh"
|
||||
|
||||
# Source configuration
|
||||
if [ -f "/etc/dropshell.conf" ]; then
|
||||
source "/etc/dropshell.conf"
|
||||
else
|
||||
echo -e "${RED}Error: Configuration file not found${NC}"
|
||||
echo "Please run the installation script first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if USER_DEFINITIONS is set
|
||||
if [ -z "$USER_DEFINITIONS" ]; then
|
||||
echo -e "${RED}Error: USER_DEFINITIONS not set${NC}"
|
||||
echo "Please run the installation script first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to print usage
|
||||
print_usage() {
|
||||
echo "Usage: $0 <command> [options]"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " help - Show this help message"
|
||||
echo " version - Show version information"
|
||||
echo " status - Check system status"
|
||||
echo " servers - List configured servers"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -v, --verbose Enable verbose output"
|
||||
}
|
||||
|
||||
# Function to print version
|
||||
print_version() {
|
||||
get_version_info
|
||||
}
|
||||
|
||||
# Function to check status
|
||||
check_status() {
|
||||
echo -e "${GREEN}System Status:${NC}"
|
||||
echo "Date: $(date)"
|
||||
echo "Uptime: $(uptime)"
|
||||
echo "Memory Usage:"
|
||||
free -h
|
||||
echo
|
||||
echo "Disk Usage:"
|
||||
df -h /
|
||||
}
|
||||
|
||||
# Function to list servers from _server.env files
|
||||
list_servers() {
|
||||
local servers_dir="/opt/dropshell/user/servers"
|
||||
local max_name_len=0
|
||||
local max_addr_len=0
|
||||
local servers=()
|
||||
|
||||
# First pass: collect data and find max lengths
|
||||
for server_dir in "$servers_dir"/*/; do
|
||||
if [ -f "${server_dir}_server.env" ]; then
|
||||
local server_name=$(basename "$server_dir")
|
||||
local ssh_address=$(grep '^SSH_ADDRESS=' "${server_dir}_server.env" | cut -d'=' -f2-)
|
||||
|
||||
# Update max lengths
|
||||
[ ${#server_name} -gt $max_name_len ] && max_name_len=${#server_name}
|
||||
[ ${#ssh_address} -gt $max_addr_len ] && max_addr_len=${#ssh_address}
|
||||
|
||||
servers+=("$server_name|$ssh_address")
|
||||
fi
|
||||
done
|
||||
|
||||
# Add padding for headers
|
||||
max_name_len=$((max_name_len > 4 ? max_name_len : 4))
|
||||
max_addr_len=$((max_addr_len > 7 ? max_addr_len : 7))
|
||||
|
||||
# Print header
|
||||
printf "%-${max_name_len}s | %-${max_addr_len}s\n" "Name" "Address"
|
||||
printf "%-${max_name_len}s-+-%-${max_addr_len}s\n" "$(printf '%*s' $max_name_len '' | tr ' ' '-')" "$(printf '%*s' $max_addr_len '' | tr ' ' '-')"
|
||||
|
||||
# Print server rows
|
||||
for server in "${servers[@]}"; do
|
||||
IFS='|' read -r name addr <<< "$server"
|
||||
printf "%-${max_name_len}s | %-${max_addr_len}s\n" "$name" "$addr"
|
||||
done
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
case "$1" in
|
||||
"help"|"-h"|"--help")
|
||||
print_usage
|
||||
;;
|
||||
"version"|"-V"|"--version")
|
||||
print_version
|
||||
;;
|
||||
"status")
|
||||
check_status
|
||||
;;
|
||||
"servers")
|
||||
list_servers
|
||||
;;
|
||||
"")
|
||||
echo -e "${RED}Error: No command provided${NC}"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Error: Unknown command '$1'${NC}"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
24
src/help.cpp
Normal file
24
src/help.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
void print_help(const boost::program_options::options_description& desc) {
|
||||
std::cout << "Usage: dropshell [OPTIONS] COMMAND [ARGS]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "A tool for managing server configurations" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Commands:" << std::endl;
|
||||
std::cout << " help Show this help message" << std::endl;
|
||||
std::cout << " version Show version information" << std::endl;
|
||||
std::cout << " init DIR Initialize the user directory for server configurations" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << " status Check system status" << std::endl;
|
||||
std::cout << " servers List configured servers" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Examples:" << std::endl;
|
||||
std::cout << " dropshell servers" << std::endl;
|
||||
std::cout << " dropshell init /path/to/directory" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
84
src/main.cpp
Normal file
84
src/main.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
// Define command line options
|
||||
po::options_description desc("Usage: dropshell <command> [options]");
|
||||
desc.add_options()
|
||||
("help,h", "Show help message")
|
||||
("version,V", "Show version information")
|
||||
("command", po::value<std::string>(), "Command to execute")
|
||||
("directory", po::value<std::string>(), "Directory path for init command")
|
||||
("verbose,v", "Enable verbose output");
|
||||
|
||||
po::positional_options_description p;
|
||||
p.add("command", 1);
|
||||
p.add("directory", 1); // Add directory as a positional argument
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(argc, argv)
|
||||
.options(desc)
|
||||
.positional(p)
|
||||
.run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
// Load configuration
|
||||
if (!dropshell::load_config()) {
|
||||
std::cerr << "Error: Failed to load configuration" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Handle commands
|
||||
if (vm.count("help") || (vm.count("command") && vm["command"].as<std::string>() == "help")) {
|
||||
dropshell::print_help(desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count("version") || (vm.count("command") && vm["command"].as<std::string>() == "version")) {
|
||||
dropshell::print_version();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count("command")) {
|
||||
std::string cmd = vm["command"].as<std::string>();
|
||||
if (cmd == "status") {
|
||||
dropshell::check_status();
|
||||
return 0;
|
||||
} else if (cmd == "servers") {
|
||||
dropshell::list_servers();
|
||||
return 0;
|
||||
} else if (cmd == "init") {
|
||||
if (!vm.count("directory")) {
|
||||
std::cerr << "Error: init command requires a directory argument" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
dropshell::init_user_directory(vm["directory"].as<std::string>());
|
||||
return 0;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Error: Unknown command '" << cmd << "'" << std::endl;
|
||||
dropshell::print_help(desc);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// No command provided
|
||||
std::cerr << "Error: No command provided" << std::endl;
|
||||
dropshell::print_help(desc);
|
||||
return 1;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
89
src/servers.cpp
Normal file
89
src/servers.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
std::vector<ServerInfo> get_configured_servers() {
|
||||
std::vector<ServerInfo> servers;
|
||||
std::string user_dir;
|
||||
|
||||
if (!is_config_loaded()) {
|
||||
std::cerr << "Error: Config not loaded" << std::endl;
|
||||
return servers;
|
||||
}
|
||||
if (!get_user_directory(user_dir)) {
|
||||
std::cerr << "Error: User directory not set" << std::endl;
|
||||
return servers;
|
||||
}
|
||||
fs::path servers_dir = fs::path(user_dir) / "servers";
|
||||
if (!fs::exists(servers_dir)) {
|
||||
return servers;
|
||||
}
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(servers_dir)) {
|
||||
if (fs::is_directory(entry)) {
|
||||
fs::path env_file = entry.path() / "_server.env";
|
||||
if (fs::exists(env_file)) {
|
||||
std::ifstream file(env_file.string());
|
||||
std::string line;
|
||||
std::string address;
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
if (boost::starts_with(line, "SSH_ADDRESS=")) {
|
||||
address = line.substr(12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!address.empty()) {
|
||||
servers.push_back({
|
||||
entry.path().filename().string(),
|
||||
address
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
void list_servers() {
|
||||
auto servers = get_configured_servers();
|
||||
|
||||
if (servers.empty()) {
|
||||
std::cout << "No servers configured." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find maximum lengths for formatting
|
||||
size_t max_name_len = 4; // "Name" is 4 chars
|
||||
size_t max_addr_len = 7; // "Address" is 7 chars
|
||||
|
||||
for (const auto& server : servers) {
|
||||
max_name_len = std::max(max_name_len, server.name.length());
|
||||
max_addr_len = std::max(max_addr_len, server.address.length());
|
||||
}
|
||||
|
||||
// Print header
|
||||
std::cout << std::left << std::setw(max_name_len) << "Name" << " | "
|
||||
<< std::setw(max_addr_len) << "Address" << std::endl;
|
||||
|
||||
// Print separator
|
||||
std::cout << std::string(max_name_len, '-') << "-+-"
|
||||
<< std::string(max_addr_len, '-') << std::endl;
|
||||
|
||||
// Print server rows
|
||||
for (const auto& server : servers) {
|
||||
std::cout << std::left << std::setw(max_name_len) << server.name << " | "
|
||||
<< std::setw(max_addr_len) << server.address << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
58
src/status.cpp
Normal file
58
src/status.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
void check_status() {
|
||||
// Get current time
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time = std::chrono::system_clock::to_time_t(now);
|
||||
std::cout << "System Status:" << std::endl;
|
||||
std::cout << "Date: " << std::ctime(&time);
|
||||
|
||||
// Get uptime
|
||||
struct sysinfo si;
|
||||
if (sysinfo(&si) == 0) {
|
||||
int days = si.uptime / 86400;
|
||||
int hours = (si.uptime % 86400) / 3600;
|
||||
int minutes = (si.uptime % 3600) / 60;
|
||||
std::cout << "Uptime: " << days << " days, " << hours << " hours, " << minutes << " minutes" << std::endl;
|
||||
}
|
||||
|
||||
// Get memory usage
|
||||
std::ifstream meminfo("/proc/meminfo");
|
||||
if (meminfo.is_open()) {
|
||||
std::string line;
|
||||
long total_mem = 0, free_mem = 0;
|
||||
while (std::getline(meminfo, line)) {
|
||||
if (line.find("MemTotal:") == 0) {
|
||||
total_mem = std::stol(line.substr(9));
|
||||
} else if (line.find("MemAvailable:") == 0) {
|
||||
free_mem = std::stol(line.substr(13));
|
||||
}
|
||||
}
|
||||
std::cout << "Memory Usage:" << std::endl;
|
||||
std::cout << "Total: " << total_mem / 1024 << " MB" << std::endl;
|
||||
std::cout << "Available: " << free_mem / 1024 << " MB" << std::endl;
|
||||
}
|
||||
|
||||
// Get disk usage
|
||||
struct statvfs vfs;
|
||||
if (statvfs("/", &vfs) == 0) {
|
||||
uint64_t total = vfs.f_blocks * vfs.f_frsize;
|
||||
uint64_t free = vfs.f_bfree * vfs.f_frsize;
|
||||
uint64_t used = total - free;
|
||||
|
||||
std::cout << "Disk Usage:" << std::endl;
|
||||
std::cout << "Total: " << total / (1024*1024*1024) << " GB" << std::endl;
|
||||
std::cout << "Used: " << used / (1024*1024*1024) << " GB" << std::endl;
|
||||
std::cout << "Free: " << free / (1024*1024*1024) << " GB" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
13
src/version.cpp
Normal file
13
src/version.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "dropshell.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
void print_version() {
|
||||
std::cout << "dropshell version " << VERSION << std::endl;
|
||||
std::cout << "Release date: " << RELEASE_DATE << std::endl;
|
||||
std::cout << "Author: " << AUTHOR << std::endl;
|
||||
std::cout << "License: " << LICENSE << std::endl;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Version information
|
||||
DROPSHELL_VERSION="1.0.0"
|
||||
DROPSHELL_RELEASE_DATE="2025-04-21"
|
||||
DROPSHELL_AUTHOR="j842"
|
||||
DROPSHELL_LICENSE="MIT"
|
||||
|
||||
# Function to get full version information
|
||||
get_version_info() {
|
||||
echo "dropshell version $DROPSHELL_VERSION"
|
||||
echo "Release date: $DROPSHELL_RELEASE_DATE"
|
||||
echo "Author: $DROPSHELL_AUTHOR"
|
||||
echo "License: $DROPSHELL_LICENSE"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user