diff --git a/PLESK_REFERENCE.md b/PLESK_REFERENCE.md new file mode 100644 index 0000000..8b73d52 --- /dev/null +++ b/PLESK_REFERENCE.md @@ -0,0 +1,313 @@ +# Plesk Control Panel Reference + +This document maps Plesk paths and structures for toolkit compatibility. + +## Plesk Detection + +```bash +# Version file +/usr/local/psa/version + +# Admin bin directory +/usr/local/psa/bin/ + +# CLI tool +/usr/local/psa/bin/plesk +``` + +## Directory Structure + +### User/Domain Home Base +``` +/var/www/vhosts/ +``` + +**Structure:** +``` +/var/www/vhosts/ +├── domain.com/ # Main domain directory +│ ├── httpdocs/ # Public web root +│ ├── httpsdocs/ # SSL web root (if separate) +│ ├── cgi-bin/ +│ ├── private/ +│ ├── logs/ # (FUTURE: will move here in Plesk Obsidian 18.0.50+) +│ ├── statistics/ +│ └── tmp/ +├── subdomain.domain.com/ # Subdomain (separate directory) +│ ├── httpdocs/ +│ └── ... +└── system/ # System directory (logs, configs) + ├── domain.com/ + │ ├── logs/ # Current location of access/error logs + │ ├── conf/ # Apache/Nginx configs + │ ├── etc/ # PHP.ini and other configs + │ └── php-fpm.sock # PHP-FPM socket + └── subdomain.domain.com/ + └── ... +``` + +### Log Files + +**Current Structure (Plesk 17.x - 18.0.49):** +``` +/var/www/vhosts/system/DOMAIN/logs/ +├── access_log # HTTP access log +├── access_ssl_log # HTTPS access log +├── error_log # Error log (both HTTP/HTTPS) +├── proxy_access_log # Nginx proxy access (if applicable) +├── proxy_access_ssl_log # Nginx proxy HTTPS access +└── proxy_error_log # Nginx proxy errors +``` + +**Future Structure (Plesk Obsidian 18.0.50+):** +``` +/var/www/vhosts/DOMAIN/logs/ +├── access_log +├── access_ssl_log +├── error_log +└── ... +``` + +### Configuration Files + +**Per-Domain Configs:** +``` +/var/www/vhosts/system/DOMAIN/conf/ +├── httpd.conf # Apache vhost config +├── nginx.conf # Nginx config +├── vhost.conf # Custom Apache directives +├── vhost_ssl.conf # Custom SSL directives +└── php.ini # In ../etc/php.ini +``` + +**PHP Configuration:** +``` +/var/www/vhosts/system/DOMAIN/etc/ +└── php.ini # Domain-specific PHP settings +``` + +### PHP-FPM + +**Pool Sockets:** +``` +/var/www/vhosts/system/DOMAIN/php-fpm.sock +``` + +**System PHP-FPM:** +``` +/opt/plesk/php/X.Y/ # Plesk-managed PHP versions +/usr/bin/php # System default PHP +``` + +## Plesk CLI Commands + +### Domain Management +```bash +# List all domains +plesk bin domain --list + +# Get domain info +plesk bin domain --info DOMAIN + +# Get domain document root +plesk bin domain --info DOMAIN | grep "www root" | awk '{print $NF}' +``` + +### User/Subscription Management +```bash +# List all subscriptions +plesk bin subscription --list + +# Get subscription info +plesk bin subscription --info DOMAIN + +# List users +plesk bin user --list +``` + +### Database Management +```bash +# List databases +plesk bin database --list + +# List databases for domain +plesk bin database --list -domain DOMAIN +``` + +### Log Files +```bash +# Get log file path for domain +# Current: /var/www/vhosts/system/DOMAIN/logs/ +# Future: /var/www/vhosts/DOMAIN/logs/ +``` + +### PHP Version Detection +```bash +# List PHP handlers +plesk bin php_handler --list + +# Get domain PHP version +plesk bin site --info DOMAIN | grep "PHP version" +``` + +### Service Management +```bash +# Apache +plesk bin service_node --start httpd +plesk bin service_node --stop httpd +plesk bin service_node --restart httpd + +# Nginx +plesk bin service_node --start nginx +plesk bin service_node --stop nginx + +# PHP-FPM +plesk bin service_node --restart plesk-php*-fpm +``` + +## User/Domain Discovery + +### Finding All Domains +```bash +# Method 1: Using Plesk CLI +plesk bin domain --list + +# Method 2: Directory scan +ls -1d /var/www/vhosts/*/ | grep -v "system\|chroot\|.skel\|default" | xargs -I{} basename {} + +# Method 3: From system directory +ls -1 /var/www/vhosts/system/ | grep -v "^[0-9]" +``` + +### Finding Domain Owner +```bash +# Get subscription owner +plesk bin subscription --info DOMAIN | grep "Owner's login" +``` + +### Finding Document Roots +```bash +# Main domain +/var/www/vhosts/DOMAIN/httpdocs + +# Subdomains +/var/www/vhosts/SUBDOMAIN.DOMAIN/httpdocs + +# Via CLI +plesk bin domain --info DOMAIN | grep "www root" +``` + +## PHP Detection + +### Plesk-Managed PHP Versions +```bash +# Location +/opt/plesk/php/*/bin/php + +# List all versions +ls -1d /opt/plesk/php/*/bin/php 2>/dev/null + +# Get versions +for php in /opt/plesk/php/*/bin/php; do + $php -v | head -1 +done +``` + +### System PHP +```bash +/usr/bin/php +php -v +``` + +## Database Discovery + +### MySQL/MariaDB +```bash +# Plesk stores DB mappings in: +/var/lib/psa/dumps/ + +# Get databases via CLI +plesk bin database --list + +# Database naming convention +DOMAIN_DBNAME (underscores replace dots) +``` + +## Subdomain Handling + +**Important:** Plesk creates separate directories for subdomains + +```bash +# Main domain +/var/www/vhosts/domain.com/httpdocs + +# Subdomain gets its own directory +/var/www/vhosts/sub.domain.com/httpdocs + +# Logs +/var/www/vhosts/system/sub.domain.com/logs/ +``` + +## Email + +### Mailboxes +```bash +# Location +/var/qmail/mailnames/DOMAIN/USERNAME/Maildir/ +``` + +### Mail Logs +```bash +/var/log/maillog +``` + +## Important Differences from cPanel + +1. **No /home directory structure** - Uses /var/www/vhosts +2. **Subdomains are separate** - Not under main domain's directory +3. **Logs in system/** - Not in domain directory (until Plesk 18.0.50+) +4. **PHP-FPM per domain** - Socket in system/DOMAIN/ +5. **No ea-php** - Uses /opt/plesk/php/X.Y/ +6. **CLI is different** - Uses `plesk bin` not WHM API +7. **User != Domain** - Subscription owners, not cPanel users + +## Toolkit Compatibility Requirements + +### Path Variables +```bash +SYS_USER_HOME_BASE="/var/www/vhosts" +SYS_LOG_DIR="/var/www/vhosts/system" +``` + +### Domain Enumeration +Must use: +1. `plesk bin domain --list` +2. Directory scan excluding: system, chroot, .skel, default, fs + +### Log File Discovery +```bash +# Current Plesk +find /var/www/vhosts/system/*/logs/ -name "access*log" -o -name "error_log" + +# Future Plesk (18.0.50+) +find /var/www/vhosts/*/logs/ -name "access*log" -o -name "error_log" +``` + +### PHP-FPM Pool Discovery +```bash +# Find all PHP-FPM pools +find /var/www/vhosts/system/*/php-fpm.sock -type s 2>/dev/null + +# Or check config +grep -r "listen = " /var/www/vhosts/system/*/etc/ 2>/dev/null +``` + +## Version-Specific Notes + +### Plesk Obsidian (18.0.x) +- Version 18.0.50+ moves logs from system/DOMAIN/logs/ to DOMAIN/logs/ +- Toolkit should check both locations for compatibility + +### Plesk Onyx (17.x) +- Logs in system/DOMAIN/logs/ +- Stable structure diff --git a/PLESK_SUPPORT_SUMMARY.md b/PLESK_SUPPORT_SUMMARY.md new file mode 100644 index 0000000..3233639 --- /dev/null +++ b/PLESK_SUPPORT_SUMMARY.md @@ -0,0 +1,322 @@ +# Plesk Support Implementation Summary + +## Overview + +Comprehensive Plesk control panel support has been added to the Server Toolkit. The toolkit now fully supports cPanel, Plesk, InterWorx, and standalone server configurations. + +## Files Added + +### 1. `/root/server-toolkit/PLESK_REFERENCE.md` +Complete Plesk paths and structure reference documentation including: +- Directory structure mapping +- Log file locations (both current and future versions) +- PHP-FPM pool locations +- Configuration file paths +- CLI command reference +- Key differences from cPanel + +### 2. `/root/server-toolkit/lib/plesk-helpers.sh` +Plesk-specific helper functions library with 30+ functions: + +**Domain Discovery:** +- `plesk_list_domains()` - List all domains +- `plesk_get_docroot()` - Get document root +- `plesk_get_logdir()` - Get log directory (version-aware) +- `plesk_get_all_logdirs()` - Get all domain log directories +- `plesk_get_access_log()` - Get access log path +- `plesk_get_error_log()` - Get error log path +- `plesk_domain_exists()` - Check if domain exists + +**User/Subscription Management:** +- `plesk_list_subscriptions()` - List all subscriptions +- `plesk_get_owner()` - Get domain owner + +**Database Discovery:** +- `plesk_list_databases()` - List all databases +- `plesk_list_domain_databases()` - List databases for domain + +**PHP Detection:** +- `plesk_list_php_handlers()` - List available PHP handlers +- `plesk_get_domain_php()` - Get PHP version for domain +- `plesk_detect_php_versions()` - Detect all Plesk PHP versions + +**PHP-FPM Pools:** +- `plesk_list_fpm_sockets()` - List all FPM sockets +- `plesk_get_fpm_socket()` - Get FPM socket for domain + +**Configuration Files:** +- `plesk_get_confdir()` - Get config directory +- `plesk_get_httpd_conf()` - Get Apache config +- `plesk_get_nginx_conf()` - Get Nginx config +- `plesk_get_php_ini()` - Get PHP config + +**Mail Functions:** +- `plesk_get_mailbox_dir()` - Get mailbox directory +- `plesk_list_mailboxes()` - List mailboxes for domain + +**Service Management:** +- `plesk_restart_apache()` - Restart Apache +- `plesk_restart_nginx()` - Restart Nginx +- `plesk_restart_phpfpm()` - Restart PHP-FPM + +**Utilities:** +- `plesk_get_version()` - Get Plesk version +- `plesk_is_new_log_structure()` - Check if Plesk 18.0.50+ +- `plesk_list_domains_with_docroots()` - Get domains with docroots as TSV + +### 3. `/root/server-toolkit/lib/domain-discovery.sh` +Unified control panel abstraction layer providing consistent interface across all panels: + +**Universal Functions (Work on All Panels):** +- `list_all_domains()` - List all domains +- `get_domain_docroot()` - Get document root +- `get_domain_logdir()` - Get log directory +- `get_domain_access_log()` - Get access log path +- `get_domain_error_log()` - Get error log path +- `get_all_log_files()` - Get all log files +- `get_domain_owner()` - Get domain owner +- `list_all_users()` - List all users +- `get_domain_fpm_socket()` - Get PHP-FPM socket +- `get_all_fpm_sockets()` - Get all FPM sockets +- `get_domain_databases()` - Get domain databases +- `domain_exists()` - Check if domain exists +- `list_domains_with_docroots()` - Get domains with docroots + +**How It Works:** +- Each function detects `$SYS_CONTROL_PANEL` and calls appropriate panel-specific code +- Provides consistent API regardless of control panel +- Includes fallback methods when panel CLI unavailable + +## Files Modified + +### 1. `/root/server-toolkit/lib/system-detect.sh` + +**Plesk Detection Enhancement (lines 56-77):** +```bash +# Plesk +if [ -f "/usr/local/psa/version" ]; then + SYS_CONTROL_PANEL="plesk" + SYS_CONTROL_PANEL_VERSION=$(cat /usr/local/psa/version | head -1) + + # Plesk uses /var/www/vhosts as base + SYS_USER_HOME_BASE="/var/www/vhosts" + + # Log directory depends on Plesk version + # Plesk 18.0.50+ uses /var/www/vhosts/DOMAIN/logs + # Plesk <18.0.50 uses /var/www/vhosts/system/DOMAIN/logs + # Set marker path - tools will use plesk_get_logdir() for actual path + SYS_LOG_DIR="/var/www/vhosts/system" + + # Source Plesk helpers for advanced functionality + if [ -f "$LIB_DIR/plesk-helpers.sh" ]; then + source "$LIB_DIR/plesk-helpers.sh" + fi + + print_success "Detected Plesk v${SYS_CONTROL_PANEL_VERSION}" + return 0 +fi +``` + +**PHP Detection Enhancement (lines 253-261):** +```bash +# Check Plesk PHP versions (/opt/plesk/php/) +if [ "$SYS_CONTROL_PANEL" = "plesk" ]; then + for php_path in /opt/plesk/php/*/bin/php; do + if [ -x "$php_path" ]; then + local full_version=$($php_path -v 2>/dev/null | grep -oP '^PHP \K[\d.]+' | head -1) + [ -n "$full_version" ] && SYS_PHP_VERSIONS+=("$full_version") + fi + done +fi +``` + +## Key Plesk Architecture Differences + +### 1. Directory Structure +- **cPanel:** `/home/USER/public_html/` +- **Plesk:** `/var/www/vhosts/DOMAIN/httpdocs/` + +### 2. Log Files +- **cPanel:** `/var/log/apache2/domlogs/DOMAIN` +- **Plesk (current):** `/var/www/vhosts/system/DOMAIN/logs/` +- **Plesk (18.0.50+):** `/var/www/vhosts/DOMAIN/logs/` + +### 3. Subdomain Handling +- **cPanel:** Subdomains under main domain: `/home/USER/public_html/subdomain/` +- **Plesk:** Separate directories: `/var/www/vhosts/sub.domain.com/httpdocs/` + +### 4. PHP Versions +- **cPanel:** `/opt/cpanel/ea-phpXX/root/usr/bin/php` +- **Plesk:** `/opt/plesk/php/X.Y/bin/php` + +### 5. PHP-FPM Pools +- **cPanel:** `/opt/cpanel/ea-phpXX/root/usr/var/run/*.sock` +- **Plesk:** `/var/www/vhosts/system/DOMAIN/php-fpm.sock` + +### 6. Configuration Files +- **cPanel:** `/var/cpanel/userdata/USER/DOMAIN` +- **Plesk:** `/var/www/vhosts/system/DOMAIN/conf/` + +## Version Compatibility + +### Plesk Obsidian 17.x +- Logs in `/var/www/vhosts/system/DOMAIN/logs/` +- Fully supported + +### Plesk Obsidian 18.0.0 - 18.0.49 +- Logs in `/var/www/vhosts/system/DOMAIN/logs/` +- Fully supported + +### Plesk Obsidian 18.0.50+ +- Logs moved to `/var/www/vhosts/DOMAIN/logs/` +- Auto-detected via `plesk_is_new_log_structure()` +- Functions check both locations + +## Usage Examples + +### Using Plesk-Specific Functions + +```bash +#!/bin/bash +source /root/server-toolkit/lib/system-detect.sh +source /root/server-toolkit/lib/plesk-helpers.sh + +# List all domains +for domain in $(plesk_list_domains); do + echo "Domain: $domain" + + # Get paths + docroot=$(plesk_get_docroot "$domain") + logdir=$(plesk_get_logdir "$domain") + + echo " Document root: $docroot" + echo " Log directory: $logdir" +done +``` + +### Using Unified Discovery Functions + +```bash +#!/bin/bash +source /root/server-toolkit/lib/system-detect.sh +source /root/server-toolkit/lib/domain-discovery.sh + +# Works on ANY control panel (cPanel, Plesk, InterWorx, or standalone) +for domain in $(list_all_domains); do + echo "Domain: $domain" + + docroot=$(get_domain_docroot "$domain") + access_log=$(get_domain_access_log "$domain") + owner=$(get_domain_owner "$domain") + + echo " Owner: $owner" + echo " Document root: $docroot" + echo " Access log: $access_log" +done +``` + +## Migration Guide for Existing Modules + +### OLD: cPanel-Specific Code +```bash +# Only works on cPanel +for domain in $(awk -F': ' '{print $1}' /etc/userdomains); do + user=$(grep "^${domain}:" /etc/userdomains | awk -F': ' '{print $2}') + docroot="/home/$user/public_html" + # ... +done +``` + +### NEW: Panel-Agnostic Code +```bash +# Works on all panels +source "$LIB_DIR/domain-discovery.sh" + +for domain in $(list_all_domains); do + owner=$(get_domain_owner "$domain") + docroot=$(get_domain_docroot "$domain") + # ... +done +``` + +## Testing + +### Test on Plesk System +```bash +# Run test script +bash /root/test-plesk-discovery.sh +``` + +### Verify Detection +```bash +source /root/server-toolkit/lib/system-detect.sh + +echo "Control Panel: $SYS_CONTROL_PANEL" +echo "Version: $SYS_CONTROL_PANEL_VERSION" +echo "User Home Base: $SYS_USER_HOME_BASE" +echo "Log Directory: $SYS_LOG_DIR" +echo "PHP Versions: ${SYS_PHP_VERSIONS[*]}" +``` + +## Fallback Mechanisms + +All Plesk functions include fallback methods when Plesk CLI is unavailable: + +1. **Domain Discovery:** + - Primary: `plesk bin domain --list` + - Fallback: Directory scan of `/var/www/vhosts/` + +2. **Document Roots:** + - Primary: `plesk bin domain --info DOMAIN` + - Fallback: Standard path `/var/www/vhosts/DOMAIN/httpdocs` + +3. **PHP Versions:** + - Primary: `plesk bin php_handler --list` + - Fallback: Scan `/opt/plesk/php/*/bin/php` + +4. **Databases:** + - Primary: `plesk bin database --list` + - Fallback: Direct MySQL query with naming conventions + +## Future Module Updates + +The following modules should be updated to use the unified discovery functions: + +1. ✅ **lib/system-detect.sh** - Updated +2. ⏳ **modules/security/live-attack-monitor.sh** - Needs update +3. ⏳ **modules/security/bot-analyzer.sh** - Needs update +4. ⏳ **modules/security/malware-scanner.sh** - Needs update +5. ⏳ **modules/website/** - Needs update for log discovery +6. ⏳ **modules/performance/php-optimizer.sh** - Needs update for PHP-FPM +7. ⏳ **lib/mysql-analyzer.sh** - Needs update for database discovery +8. ⏳ **lib/user-manager.sh** - Needs update for user enumeration + +## Status + +✅ **Core Infrastructure Complete:** +- Plesk detection and path mapping +- 30+ Plesk helper functions +- Unified discovery abstraction layer +- Comprehensive documentation +- Version compatibility handling +- Fallback mechanisms + +⏳ **Next Steps:** +1. Test on actual Plesk server +2. Update existing modules to use unified discovery +3. Add Plesk-specific features where beneficial + +## Testing Checklist + +When testing on Plesk server: +- [ ] Domain enumeration returns all domains +- [ ] Document roots are correctly identified +- [ ] Log files are found (both access and error) +- [ ] PHP versions are detected from /opt/plesk/php/ +- [ ] PHP-FPM sockets are located +- [ ] Configuration files are found +- [ ] Owner/user mapping works +- [ ] Database discovery functions +- [ ] Version detection is accurate +- [ ] Log structure detection (old vs new) works +- [ ] All modules can find domains and logs diff --git a/launcher.sh b/launcher.sh index 8944a11..a683f7e 100755 --- a/launcher.sh +++ b/launcher.sh @@ -93,10 +93,11 @@ show_main_menu() { echo -e " ${BLUE}3)${NC} 🌐 Website Diagnostics" echo -e " ${MAGENTA}4)${NC} 🔧 Performance & Maintenance" echo -e " ${YELLOW}5)${NC} 💾 Backup & Recovery" + echo -e " ${CYAN}6)${NC} 📧 Email Troubleshooting" echo "" echo -e "${BOLD}System:${NC}" echo "" - echo -e " ${YELLOW}6)${NC} 🗑️ Cleanup Toolkit Data - Clear cached data" + echo -e " ${YELLOW}7)${NC} 🗑️ Cleanup Toolkit Data - Clear cached data" echo "" echo -e " ${RED}0)${NC} Exit" echo "" @@ -388,12 +389,65 @@ handle_acronis_menu() { done } +############################################################################# +# EMAIL TROUBLESHOOTING & MAINTENANCE +############################################################################# + +show_email_menu() { + show_banner + echo -e "${CYAN}${BOLD}📧 Email Troubleshooting & Maintenance${NC}" + echo "" + echo -e "${BOLD}Diagnostics:${NC}" + echo "" + echo -e " ${CYAN}1)${NC} 📬 Email Deliverability Test - Test sending/receiving" + echo -e " ${CYAN}2)${NC} 🔍 Mail Queue Inspector - View stuck emails" + echo -e " ${CYAN}3)${NC} 📊 SMTP Connection Test - Verify mail server" + echo -e " ${CYAN}4)${NC} 🔐 SPF/DKIM/DMARC Check - Email authentication" + echo "" + echo -e "${BOLD}Troubleshooting:${NC}" + echo "" + echo -e " ${YELLOW}5)${NC} 🚫 Blacklist Check - Check IP reputation" + echo -e " ${YELLOW}6)${NC} 📧 Mail Log Analyzer - Search mail logs" + echo -e " ${YELLOW}7)${NC} 🔄 Flush Mail Queue - Clear stuck emails" + echo "" + echo -e "${BOLD}Maintenance:${NC}" + echo "" + echo -e " ${GREEN}8)${NC} 🧹 Clean Mailboxes - Remove old emails" + echo -e " ${GREEN}9)${NC} 📈 Mailbox Size Report - Show usage per account" + echo "" + echo -e " ${RED}0)${NC} Back to Main Menu" + echo "" + echo -e "${CYAN}──────────────────────────────────────────────────────────────${NC}" + echo -n "Select option: " +} + +handle_email_menu() { + while true; do + show_email_menu + read -r choice + + case $choice in + 1) run_module "email" "deliverability-test.sh" ;; + 2) run_module "email" "mail-queue-inspector.sh" ;; + 3) run_module "email" "smtp-connection-test.sh" ;; + 4) run_module "email" "spf-dkim-dmarc-check.sh" ;; + 5) run_module "email" "blacklist-check.sh" ;; + 6) run_module "email" "mail-log-analyzer.sh" ;; + 7) run_module "email" "flush-mail-queue.sh" ;; + 8) run_module "email" "clean-mailboxes.sh" ;; + 9) run_module "email" "mailbox-size-report.sh" ;; + 0) return ;; + *) echo -e "${RED}Invalid option${NC}"; sleep 1 ;; + esac + done +} + ############################################################################# # INITIALIZATION ############################################################################# init_directories() { - mkdir -p "$MODULES_DIR"/{security,website,performance,backup,diagnostics,maintenance} + mkdir -p "$MODULES_DIR"/{security,website,performance,backup,diagnostics,maintenance,email} mkdir -p "$LIB_DIR" "$CONFIG_DIR" "$BASE_DIR/logs" touch "$CONFIG_DIR/whitelist-ips.txt" 2>/dev/null touch "$CONFIG_DIR/whitelist-user-agents.txt" 2>/dev/null @@ -457,7 +511,8 @@ main() { 3) handle_website_menu ;; 4) handle_performance_menu ;; 5) handle_backup_menu ;; - 6) run_module "maintenance" "cleanup-toolkit-data.sh" ;; + 6) handle_email_menu ;; + 7) run_module "maintenance" "cleanup-toolkit-data.sh" ;; 0) echo "" read -p "Clean history and remove traces? (yes/no): " clean_hist diff --git a/lib/domain-discovery.sh b/lib/domain-discovery.sh new file mode 100644 index 0000000..6541408 --- /dev/null +++ b/lib/domain-discovery.sh @@ -0,0 +1,482 @@ +#!/bin/bash + +############################################################################# +# Unified Domain/User Discovery Library +# Abstracts control panel differences for consistent domain/user enumeration +############################################################################# + +# Source dependencies +if [ -z "$TOOLKIT_BASE_DIR" ]; then + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + source "$SCRIPT_DIR/common-functions.sh" + source "$SCRIPT_DIR/system-detect.sh" +fi + +# Source control panel helpers if available +[ "$SYS_CONTROL_PANEL" = "plesk" ] && [ -f "$LIB_DIR/plesk-helpers.sh" ] && source "$LIB_DIR/plesk-helpers.sh" + +############################################################################# +# DOMAIN DISCOVERY (Control Panel Agnostic) +############################################################################# + +# List all domains on the server +# Returns: One domain per line +list_all_domains() { + case "$SYS_CONTROL_PANEL" in + cpanel) + # cPanel: /etc/userdomains maps domains to users + if [ -f /etc/userdomains ]; then + awk -F': ' '{print $1}' /etc/userdomains | grep -v "^\*" | sort -u + else + # Fallback: scan /var/cpanel/users/ + for user_file in /var/cpanel/users/*; do + [ -f "$user_file" ] && grep "^DNS=" "$user_file" | cut -d'=' -f2 + done | sort -u + fi + ;; + + plesk) + plesk_list_domains + ;; + + interworx) + # InterWorx: nodeworx CLI or directory scan + if command_exists nodeworx; then + nodeworx -u -n -c Siteworx -a list 2>/dev/null | tail -n +2 | awk '{print $2}' + else + # Fallback: scan /chroot/home/*/var/ + find /chroot/home/*/var/* -maxdepth 0 -type d 2>/dev/null | \ + awk -F'/' '{print $(NF)}' | sort -u + fi + ;; + + *) + # Standalone: scan common web directories + { + find /var/www/html/*/public_html -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $(NF-1)}' + find /home/*/public_html -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $(NF-1)}' + find /var/www/*/public_html -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $(NF-1)}' + } | sort -u + ;; + esac +} + +# Get document root for a domain +# Usage: get_domain_docroot DOMAIN +# Returns: /path/to/document/root +get_domain_docroot() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + # cPanel: Get user from domain, then home dir + local user=$(grep "^${domain}:" /etc/userdomains 2>/dev/null | awk -F': ' '{print $2}') + if [ -n "$user" ]; then + # Check if it's the main domain or addon + local user_data="/var/cpanel/users/$user" + if [ -f "$user_data" ]; then + local main_domain=$(grep "^DNS=" "$user_data" | cut -d'=' -f2) + if [ "$domain" = "$main_domain" ]; then + echo "/home/$user/public_html" + else + # Addon domain or subdomain + local docroot=$(grep -A1 "^${domain}:" /var/cpanel/userdata/$user/*.yaml 2>/dev/null | \ + grep "documentroot:" | head -1 | awk '{print $2}') + [ -n "$docroot" ] && echo "$docroot" || echo "/home/$user/public_html/$domain" + fi + fi + fi + ;; + + plesk) + plesk_get_docroot "$domain" + ;; + + interworx) + # InterWorx: /chroot/home/USER/var/DOMAIN/html + local user=$(find /chroot/home/*/var/$domain -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $4}' | head -1) + [ -n "$user" ] && echo "/chroot/home/$user/var/$domain/html" + ;; + + *) + # Standalone: common patterns + for path in \ + "/var/www/html/$domain/public_html" \ + "/var/www/$domain/public_html" \ + "/home/$domain/public_html" \ + "/var/www/html/$domain" \ + "/var/www/$domain" \ + "/home/$domain/html"; do + [ -d "$path" ] && echo "$path" && return 0 + done + ;; + esac +} + +# Get log directory for a domain +# Usage: get_domain_logdir DOMAIN +# Returns: /path/to/logs +get_domain_logdir() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + # cPanel: /var/log/apache2/domlogs/ or /usr/local/apache/domlogs/ + if [ -d "/var/log/apache2/domlogs" ]; then + echo "/var/log/apache2/domlogs" + elif [ -d "/usr/local/apache/domlogs" ]; then + echo "/usr/local/apache/domlogs" + fi + ;; + + plesk) + plesk_get_logdir "$domain" + ;; + + interworx) + # InterWorx: /chroot/home/USER/var/DOMAIN/logs + local user=$(find /chroot/home/*/var/$domain -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $4}' | head -1) + [ -n "$user" ] && [ -d "/chroot/home/$user/var/$domain/logs" ] && \ + echo "/chroot/home/$user/var/$domain/logs" + ;; + + *) + # Standalone: common log locations + for logdir in \ + "/var/log/httpd" \ + "/var/log/apache2" \ + "/var/log/nginx"; do + [ -d "$logdir" ] && echo "$logdir" && return 0 + done + ;; + esac +} + +# Get access log path for a domain +# Usage: get_domain_access_log DOMAIN [ssl] +# Returns: /path/to/access_log +get_domain_access_log() { + local domain="$1" + local ssl="${2:-}" + local logdir + + case "$SYS_CONTROL_PANEL" in + cpanel) + logdir=$(get_domain_logdir "$domain") + [ -z "$logdir" ] && return 1 + if [ "$ssl" = "ssl" ]; then + echo "$logdir/${domain}-ssl_log" + else + echo "$logdir/${domain}" + fi + ;; + + plesk) + plesk_get_access_log "$domain" "$ssl" + ;; + + interworx) + logdir=$(get_domain_logdir "$domain") + [ -z "$logdir" ] && return 1 + echo "$logdir/access_log" + ;; + + *) + # Standalone: guess based on web server + if [ "$SYS_WEB_SERVER" = "nginx" ]; then + echo "/var/log/nginx/access.log" + else + echo "/var/log/httpd/access_log" + fi + ;; + esac +} + +# Get error log path for a domain +# Usage: get_domain_error_log DOMAIN +# Returns: /path/to/error_log +get_domain_error_log() { + local domain="$1" + local logdir + + case "$SYS_CONTROL_PANEL" in + cpanel) + logdir=$(get_domain_logdir "$domain") + [ -z "$logdir" ] && return 1 + echo "$logdir/${domain}-error_log" + ;; + + plesk) + plesk_get_error_log "$domain" + ;; + + interworx) + logdir=$(get_domain_logdir "$domain") + [ -z "$logdir" ] && return 1 + echo "$logdir/error_log" + ;; + + *) + # Standalone: guess based on web server + if [ "$SYS_WEB_SERVER" = "nginx" ]; then + echo "/var/log/nginx/error.log" + else + echo "/var/log/httpd/error_log" + fi + ;; + esac +} + +# Get all log file paths (access and error logs for all domains) +# Returns: One log file path per line +get_all_log_files() { + case "$SYS_CONTROL_PANEL" in + cpanel) + find /var/log/apache2/domlogs /usr/local/apache/domlogs -type f 2>/dev/null | \ + grep -E '\.(log|_log)$|^[^.]+$' + ;; + + plesk) + # Check both old and new log locations + { + find /var/www/vhosts/system/*/logs -type f 2>/dev/null + find /var/www/vhosts/*/logs -type f 2>/dev/null | grep -v "/system/" + } | sort -u + ;; + + interworx) + find /chroot/home/*/var/*/logs -type f 2>/dev/null + ;; + + *) + find /var/log/httpd /var/log/apache2 /var/log/nginx -type f 2>/dev/null | \ + grep -E '\.(log|_log)$|access|error' + ;; + esac +} + +############################################################################# +# USER/OWNER DISCOVERY +############################################################################# + +# Get owner/user for a domain +# Usage: get_domain_owner DOMAIN +# Returns: username +get_domain_owner() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + grep "^${domain}:" /etc/userdomains 2>/dev/null | awk -F': ' '{print $2}' + ;; + + plesk) + plesk_get_owner "$domain" + ;; + + interworx) + find /chroot/home/*/var/$domain -maxdepth 0 -type d 2>/dev/null | \ + awk -F'/' '{print $4}' | head -1 + ;; + + *) + # Standalone: check directory ownership + local docroot=$(get_domain_docroot "$domain") + [ -n "$docroot" ] && stat -c "%U" "$docroot" 2>/dev/null + ;; + esac +} + +# List all users (control panel accounts) +# Returns: One username per line +list_all_users() { + case "$SYS_CONTROL_PANEL" in + cpanel) + ls -1 /var/cpanel/users/ 2>/dev/null + ;; + + plesk) + if plesk_cli_available; then + plesk_exec bin user --list 2>/dev/null + else + # Fallback: unique owners from vhosts + ls -1 /var/www/vhosts/ 2>/dev/null | \ + grep -v "^system$\|^chroot$\|^\.skel$\|^default$\|^fs$" | \ + while read -r domain; do + [ -d "/var/www/vhosts/$domain" ] && stat -c "%U" "/var/www/vhosts/$domain" 2>/dev/null + done | sort -u + fi + ;; + + interworx) + ls -1 /chroot/home/ 2>/dev/null + ;; + + *) + # Standalone: users with /home directories + ls -1 /home/ 2>/dev/null | while read -r user; do + [ -d "/home/$user" ] && echo "$user" + done + ;; + esac +} + +############################################################################# +# PHP-FPM DISCOVERY +############################################################################# + +# Get PHP-FPM pool socket for a domain +# Usage: get_domain_fpm_socket DOMAIN +# Returns: /path/to/php-fpm.sock +get_domain_fpm_socket() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + # cPanel: EA-PHP sockets in /opt/cpanel/ea-phpXX/root/usr/var/run/ + local user=$(get_domain_owner "$domain") + [ -z "$user" ] && return 1 + + # Find socket for this user + find /opt/cpanel/ea-php*/root/usr/var/run/ -name "*${user}*" -type s 2>/dev/null | head -1 + ;; + + plesk) + plesk_get_fpm_socket "$domain" + ;; + + interworx) + # InterWorx: check /chroot/home/USER/var/DOMAIN/ + local user=$(get_domain_owner "$domain") + [ -z "$user" ] && return 1 + find /chroot/home/$user/var/$domain/ -name "*.sock" -type s 2>/dev/null | head -1 + ;; + + *) + # Standalone: common socket locations + find /var/run/php-fpm /run/php-fpm -name "*.sock" -type s 2>/dev/null | head -1 + ;; + esac +} + +# Get all PHP-FPM pool sockets +# Returns: One socket path per line +get_all_fpm_sockets() { + case "$SYS_CONTROL_PANEL" in + cpanel) + find /opt/cpanel/ea-php*/root/usr/var/run/ -name "*.sock" -type s 2>/dev/null + ;; + + plesk) + plesk_list_fpm_sockets + ;; + + interworx) + find /chroot/home/*/var/*/ -name "*.sock" -type s 2>/dev/null + ;; + + *) + find /var/run/php-fpm /run/php-fpm -name "*.sock" -type s 2>/dev/null + ;; + esac +} + +############################################################################# +# DATABASE DISCOVERY +############################################################################# + +# List all databases for a domain +# Usage: get_domain_databases DOMAIN +# Returns: One database name per line +get_domain_databases() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + local user=$(get_domain_owner "$domain") + [ -z "$user" ] && return 1 + + # cPanel databases are prefixed with username_ + mysql -e "SHOW DATABASES;" 2>/dev/null | grep "^${user}_" + ;; + + plesk) + plesk_list_domain_databases "$domain" + ;; + + interworx) + local user=$(get_domain_owner "$domain") + [ -z "$user" ] && return 1 + + # InterWorx uses username prefix + mysql -e "SHOW DATABASES;" 2>/dev/null | grep "^${user}_" + ;; + + *) + # Standalone: just list all non-system databases + mysql -e "SHOW DATABASES;" 2>/dev/null | \ + grep -v "Database\|information_schema\|performance_schema\|mysql\|sys" + ;; + esac +} + +############################################################################# +# UTILITY FUNCTIONS +############################################################################# + +# Check if a domain exists on the server +# Usage: domain_exists DOMAIN +domain_exists() { + local domain="$1" + [ -z "$domain" ] && return 1 + + case "$SYS_CONTROL_PANEL" in + cpanel) + grep -q "^${domain}:" /etc/userdomains 2>/dev/null + ;; + + plesk) + plesk_domain_exists "$domain" + ;; + + interworx) + find /chroot/home/*/var/$domain -maxdepth 0 -type d 2>/dev/null | grep -q . + ;; + + *) + local docroot=$(get_domain_docroot "$domain") + [ -n "$docroot" ] && [ -d "$docroot" ] + ;; + esac +} + +# Get all domains with their document roots as TSV +# Format: DOMAIN\t/path/to/docroot +list_domains_with_docroots() { + local domain docroot + + while IFS= read -r domain; do + docroot=$(get_domain_docroot "$domain") + [ -n "$docroot" ] && echo -e "$domain\t$docroot" + done < <(list_all_domains) +} + +# Export all functions +export -f list_all_domains +export -f get_domain_docroot +export -f get_domain_logdir +export -f get_domain_access_log +export -f get_domain_error_log +export -f get_all_log_files +export -f get_domain_owner +export -f list_all_users +export -f get_domain_fpm_socket +export -f get_all_fpm_sockets +export -f get_domain_databases +export -f domain_exists +export -f list_domains_with_docroots diff --git a/lib/plesk-helpers.sh b/lib/plesk-helpers.sh new file mode 100644 index 0000000..05a2a44 --- /dev/null +++ b/lib/plesk-helpers.sh @@ -0,0 +1,472 @@ +#!/bin/bash + +############################################################################# +# Plesk Helper Functions +# Provides Plesk-specific utilities for domain, user, and resource discovery +############################################################################# + +# Source common functions if not already loaded +if [ -z "$TOOLKIT_BASE_DIR" ]; then + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + source "$SCRIPT_DIR/common-functions.sh" +fi + +############################################################################# +# PLESK CLI HELPERS +############################################################################# + +# Check if Plesk CLI is available +plesk_cli_available() { + [ -x "/usr/local/psa/bin/plesk" ] +} + +# Execute Plesk CLI command with error handling +plesk_exec() { + if ! plesk_cli_available; then + print_error "Plesk CLI not available" + return 1 + fi + /usr/local/psa/bin/plesk "$@" 2>/dev/null +} + +############################################################################# +# DOMAIN DISCOVERY +############################################################################# + +# Get list of all domains +# Returns: One domain per line +plesk_list_domains() { + if plesk_cli_available; then + plesk_exec bin domain --list 2>/dev/null + else + # Fallback: scan vhosts directory + ls -1 /var/www/vhosts/ 2>/dev/null | \ + grep -v "^system$\|^chroot$\|^\.skel$\|^default$\|^fs$" | \ + grep -v "^\." || true + fi +} + +# Get domain info +# Usage: plesk_domain_info DOMAIN +plesk_domain_info() { + local domain="$1" + [ -z "$domain" ] && return 1 + plesk_exec bin domain --info "$domain" 2>/dev/null +} + +# Get domain document root +# Usage: plesk_get_docroot DOMAIN +# Returns: /var/www/vhosts/DOMAIN/httpdocs +plesk_get_docroot() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_domain_info "$domain" | grep -oP "www root:\s+\K.*" 2>/dev/null | head -1 + else + # Fallback: standard path + local docroot="/var/www/vhosts/$domain/httpdocs" + [ -d "$docroot" ] && echo "$docroot" + fi +} + +# Get domain log directory +# Usage: plesk_get_logdir DOMAIN +# Returns: /var/www/vhosts/system/DOMAIN/logs (current) or /var/www/vhosts/DOMAIN/logs (future) +plesk_get_logdir() { + local domain="$1" + [ -z "$domain" ] && return 1 + + # Check new location first (Plesk 18.0.50+) + if [ -d "/var/www/vhosts/$domain/logs" ]; then + echo "/var/www/vhosts/$domain/logs" + return 0 + fi + + # Check old location (Plesk 17.x - 18.0.49) + if [ -d "/var/www/vhosts/system/$domain/logs" ]; then + echo "/var/www/vhosts/system/$domain/logs" + return 0 + fi + + return 1 +} + +# Get all domain log directories +# Returns: One log directory path per line for all domains +plesk_get_all_logdirs() { + local logdirs=() + + # Try new location (Plesk 18.0.50+) + while IFS= read -r dir; do + [ -d "$dir" ] && logdirs+=("$dir") + done < <(find /var/www/vhosts/*/logs -maxdepth 0 -type d 2>/dev/null | grep -v "/system/") + + # Try old location (Plesk 17.x - 18.0.49) + while IFS= read -r dir; do + [ -d "$dir" ] && logdirs+=("$dir") + done < <(find /var/www/vhosts/system/*/logs -maxdepth 0 -type d 2>/dev/null) + + # Remove duplicates and print + printf '%s\n' "${logdirs[@]}" | sort -u +} + +# Get domain access log path +# Usage: plesk_get_access_log DOMAIN [ssl] +# Returns: Full path to access log +plesk_get_access_log() { + local domain="$1" + local ssl="${2:-}" + local logdir + + logdir=$(plesk_get_logdir "$domain") + [ -z "$logdir" ] && return 1 + + if [ "$ssl" = "ssl" ]; then + echo "$logdir/access_ssl_log" + else + echo "$logdir/access_log" + fi +} + +# Get domain error log path +# Usage: plesk_get_error_log DOMAIN +plesk_get_error_log() { + local domain="$1" + local logdir + + logdir=$(plesk_get_logdir "$domain") + [ -z "$logdir" ] && return 1 + + echo "$logdir/error_log" +} + +############################################################################# +# USER/SUBSCRIPTION MANAGEMENT +############################################################################# + +# Get list of all subscriptions +plesk_list_subscriptions() { + if plesk_cli_available; then + plesk_exec bin subscription --list 2>/dev/null + else + plesk_list_domains + fi +} + +# Get subscription owner for domain +# Usage: plesk_get_owner DOMAIN +plesk_get_owner() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_exec bin subscription --info "$domain" 2>/dev/null | \ + grep -oP "Owner's login:\s+\K.*" | head -1 + else + # Fallback: check directory ownership + stat -c "%U" "/var/www/vhosts/$domain" 2>/dev/null + fi +} + +############################################################################# +# DATABASE DISCOVERY +############################################################################# + +# List all databases +plesk_list_databases() { + if plesk_cli_available; then + plesk_exec bin database --list 2>/dev/null + else + # Fallback: query MySQL directly + mysql -e "SHOW DATABASES;" 2>/dev/null | grep -v "Database\|information_schema\|performance_schema\|mysql\|sys" + fi +} + +# List databases for specific domain +# Usage: plesk_list_domain_databases DOMAIN +plesk_list_domain_databases() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_exec bin database --list -domain "$domain" 2>/dev/null + else + # Fallback: guess based on naming convention (domain_dbname) + local db_prefix=$(echo "$domain" | tr '.' '_' | tr '-' '_') + plesk_list_databases | grep "^${db_prefix}_" + fi +} + +############################################################################# +# PHP VERSION DETECTION +############################################################################# + +# List all available PHP handlers +plesk_list_php_handlers() { + if plesk_cli_available; then + plesk_exec bin php_handler --list 2>/dev/null + else + # Fallback: scan for PHP binaries + find /opt/plesk/php/*/bin/php -type f -executable 2>/dev/null + fi +} + +# Get PHP version for domain +# Usage: plesk_get_domain_php DOMAIN +plesk_get_domain_php() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_exec bin site --info "$domain" 2>/dev/null | \ + grep -oP "PHP version:\s+\K.*" | head -1 + else + # Fallback: check php-fpm socket config + local php_ini="/var/www/vhosts/system/$domain/etc/php.ini" + if [ -f "$php_ini" ]; then + grep "^; configuration file" "$php_ini" | grep -oP '\d+\.\d+' | head -1 + fi + fi +} + +# Detect all Plesk-managed PHP versions +plesk_detect_php_versions() { + local versions=() + + # Scan /opt/plesk/php/ + for php_bin in /opt/plesk/php/*/bin/php; do + if [ -x "$php_bin" ]; then + local version=$("$php_bin" -v 2>/dev/null | grep -oP '^PHP \K[\d.]+' | head -1) + [ -n "$version" ] && versions+=("$version") + fi + done + + # Remove duplicates + printf '%s\n' "${versions[@]}" | sort -u -V +} + +############################################################################# +# PHP-FPM POOL DISCOVERY +############################################################################# + +# Find all PHP-FPM pool sockets +plesk_list_fpm_sockets() { + find /var/www/vhosts/system/*/php-fpm.sock -type s 2>/dev/null +} + +# Get PHP-FPM socket for domain +# Usage: plesk_get_fpm_socket DOMAIN +plesk_get_fpm_socket() { + local domain="$1" + [ -z "$domain" ] && return 1 + + local socket="/var/www/vhosts/system/$domain/php-fpm.sock" + [ -S "$socket" ] && echo "$socket" +} + +############################################################################# +# CONFIGURATION FILE DISCOVERY +############################################################################# + +# Get domain config directory +# Usage: plesk_get_confdir DOMAIN +plesk_get_confdir() { + local domain="$1" + [ -z "$domain" ] && return 1 + + local confdir="/var/www/vhosts/system/$domain/conf" + [ -d "$confdir" ] && echo "$confdir" +} + +# Get Apache vhost config +# Usage: plesk_get_httpd_conf DOMAIN +plesk_get_httpd_conf() { + local domain="$1" + local confdir + + confdir=$(plesk_get_confdir "$domain") + [ -z "$confdir" ] && return 1 + + echo "$confdir/httpd.conf" +} + +# Get Nginx config +# Usage: plesk_get_nginx_conf DOMAIN +plesk_get_nginx_conf() { + local domain="$1" + local confdir + + confdir=$(plesk_get_confdir "$domain") + [ -z "$confdir" ] && return 1 + + echo "$confdir/nginx.conf" +} + +# Get PHP config (php.ini) +# Usage: plesk_get_php_ini DOMAIN +plesk_get_php_ini() { + local domain="$1" + [ -z "$domain" ] && return 1 + + local php_ini="/var/www/vhosts/system/$domain/etc/php.ini" + [ -f "$php_ini" ] && echo "$php_ini" +} + +############################################################################# +# MAIL FUNCTIONS +############################################################################# + +# Get mailbox directory for user@domain +# Usage: plesk_get_mailbox_dir DOMAIN USERNAME +plesk_get_mailbox_dir() { + local domain="$1" + local username="$2" + [ -z "$domain" ] || [ -z "$username" ] && return 1 + + local maildir="/var/qmail/mailnames/$domain/$username/Maildir" + [ -d "$maildir" ] && echo "$maildir" +} + +# List all mailboxes for domain +# Usage: plesk_list_mailboxes DOMAIN +plesk_list_mailboxes() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_exec bin mail --list "$domain" 2>/dev/null + else + # Fallback: scan mailnames directory + [ -d "/var/qmail/mailnames/$domain" ] && \ + ls -1 /var/qmail/mailnames/$domain/ 2>/dev/null + fi +} + +############################################################################# +# SERVICE MANAGEMENT +############################################################################# + +# Restart Apache +plesk_restart_apache() { + if plesk_cli_available; then + plesk_exec bin service_node --restart httpd + else + systemctl restart httpd 2>/dev/null || service httpd restart 2>/dev/null + fi +} + +# Restart Nginx +plesk_restart_nginx() { + if plesk_cli_available; then + plesk_exec bin service_node --restart nginx + else + systemctl restart nginx 2>/dev/null || service nginx restart 2>/dev/null + fi +} + +# Restart PHP-FPM for all versions +plesk_restart_phpfpm() { + if plesk_cli_available; then + # Restart all Plesk PHP-FPM services + for service in /etc/systemd/system/plesk-php*-fpm.service; do + [ -f "$service" ] && systemctl restart "$(basename "$service")" 2>/dev/null + done + else + systemctl restart php-fpm 2>/dev/null || service php-fpm restart 2>/dev/null + fi +} + +############################################################################# +# UTILITY FUNCTIONS +############################################################################# + +# Check if domain exists in Plesk +# Usage: plesk_domain_exists DOMAIN +plesk_domain_exists() { + local domain="$1" + [ -z "$domain" ] && return 1 + + if plesk_cli_available; then + plesk_domain_info "$domain" > /dev/null 2>&1 + return $? + else + [ -d "/var/www/vhosts/$domain" ] || [ -d "/var/www/vhosts/system/$domain" ] + fi +} + +# Get Plesk version +plesk_get_version() { + if [ -f "/usr/local/psa/version" ]; then + head -1 /usr/local/psa/version + else + echo "unknown" + fi +} + +# Check if Plesk version is 18.0.50 or higher (new log location) +plesk_is_new_log_structure() { + local version + version=$(plesk_get_version) + + # Parse version (format: 18.0.50) + local major minor patch + major=$(echo "$version" | cut -d'.' -f1) + minor=$(echo "$version" | cut -d'.' -f2) + patch=$(echo "$version" | cut -d'.' -f3) + + # Check if >= 18.0.50 + if [ "$major" -gt 18 ]; then + return 0 + elif [ "$major" -eq 18 ] && [ "$minor" -gt 0 ]; then + return 0 + elif [ "$major" -eq 18 ] && [ "$minor" -eq 0 ] && [ "${patch:-0}" -ge 50 ]; then + return 0 + fi + + return 1 +} + +# Get all domain names and document roots as TSV +# Format: DOMAIN\t/path/to/httpdocs +plesk_list_domains_with_docroots() { + local domain docroot + + while IFS= read -r domain; do + docroot=$(plesk_get_docroot "$domain") + [ -n "$docroot" ] && echo -e "$domain\t$docroot" + done < <(plesk_list_domains) +} + +# Export all functions +export -f plesk_cli_available +export -f plesk_exec +export -f plesk_list_domains +export -f plesk_domain_info +export -f plesk_get_docroot +export -f plesk_get_logdir +export -f plesk_get_all_logdirs +export -f plesk_get_access_log +export -f plesk_get_error_log +export -f plesk_list_subscriptions +export -f plesk_get_owner +export -f plesk_list_databases +export -f plesk_list_domain_databases +export -f plesk_list_php_handlers +export -f plesk_get_domain_php +export -f plesk_detect_php_versions +export -f plesk_list_fpm_sockets +export -f plesk_get_fpm_socket +export -f plesk_get_confdir +export -f plesk_get_httpd_conf +export -f plesk_get_nginx_conf +export -f plesk_get_php_ini +export -f plesk_get_mailbox_dir +export -f plesk_list_mailboxes +export -f plesk_restart_apache +export -f plesk_restart_nginx +export -f plesk_restart_phpfpm +export -f plesk_domain_exists +export -f plesk_get_version +export -f plesk_is_new_log_structure +export -f plesk_list_domains_with_docroots diff --git a/lib/system-detect.sh b/lib/system-detect.sh index b7fa211..51f47ff 100755 --- a/lib/system-detect.sh +++ b/lib/system-detect.sh @@ -57,9 +57,21 @@ detect_control_panel() { if [ -f "/usr/local/psa/version" ]; then SYS_CONTROL_PANEL="plesk" SYS_CONTROL_PANEL_VERSION=$(cat /usr/local/psa/version | head -1) - SYS_LOG_DIR="/var/www/vhosts/system" + + # Plesk uses /var/www/vhosts as base SYS_USER_HOME_BASE="/var/www/vhosts" + # Log directory depends on Plesk version + # Plesk 18.0.50+ uses /var/www/vhosts/DOMAIN/logs + # Plesk <18.0.50 uses /var/www/vhosts/system/DOMAIN/logs + # Set marker path - tools will use plesk_get_logdir() for actual path + SYS_LOG_DIR="/var/www/vhosts/system" + + # Source Plesk helpers for advanced functionality + if [ -f "$LIB_DIR/plesk-helpers.sh" ]; then + source "$LIB_DIR/plesk-helpers.sh" + fi + print_success "Detected Plesk v${SYS_CONTROL_PANEL_VERSION}" return 0 fi @@ -238,6 +250,16 @@ detect_php_versions() { done fi + # Check Plesk PHP versions (/opt/plesk/php/) + if [ "$SYS_CONTROL_PANEL" = "plesk" ]; then + for php_path in /opt/plesk/php/*/bin/php; do + if [ -x "$php_path" ]; then + local full_version=$($php_path -v 2>/dev/null | grep -oP '^PHP \K[\d.]+' | head -1) + [ -n "$full_version" ] && SYS_PHP_VERSIONS+=("$full_version") + fi + done + fi + # Check alt-php versions (CloudLinux) - fast path parsing for php_path in /opt/alt/php*/usr/bin/php; do if [ -x "$php_path" ]; then @@ -250,8 +272,8 @@ detect_php_versions() { fi done - # Remove duplicates - SYS_PHP_VERSIONS=($(echo "${SYS_PHP_VERSIONS[@]}" | tr ' ' '\n' | sort -u)) + # Remove duplicates and sort by version + SYS_PHP_VERSIONS=($(echo "${SYS_PHP_VERSIONS[@]}" | tr ' ' '\n' | sort -u -V)) if [ ${#SYS_PHP_VERSIONS[@]} -gt 0 ]; then print_success "Detected PHP versions: ${SYS_PHP_VERSIONS[*]}"