.
This commit is contained in:
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"
|
||||
}
|
Reference in New Issue
Block a user