Improve installation and uninstallation scripts. Add user to dialout group for serial port access in install-service.sh, and implement safety features in uninstall-service.sh, including backup options and confirmation prompts for destructive actions. Update error handling and messaging for clarity across both scripts.

This commit is contained in:
agessaman
2025-11-27 21:44:38 -08:00
parent 7982cdce4c
commit f40eda8a85
4 changed files with 1006 additions and 75 deletions

View File

@@ -189,6 +189,29 @@ else
else
print_warning "User $SERVICE_USER already exists (skipping creation)"
fi
# Add user to dialout group for serial port access (Linux)
print_info "Configuring serial port access permissions"
if getent group dialout > /dev/null 2>&1; then
if groups "$SERVICE_USER" | grep -q "\bdialout\b"; then
print_warning "User $SERVICE_USER is already in dialout group"
else
usermod -a -G dialout "$SERVICE_USER"
print_success "Added $SERVICE_USER to dialout group for serial port access"
fi
else
print_warning "dialout group not found - serial port access may require manual configuration"
print_info "If using serial connection, you may need to: sudo usermod -a -G dialout $SERVICE_USER"
fi
# Also check for other common serial port groups (tty, uucp, lock)
for group in tty uucp lock; do
if getent group "$group" > /dev/null 2>&1; then
if ! groups "$SERVICE_USER" | grep -q "\b$group\b"; then
usermod -a -G "$group" "$SERVICE_USER" 2>/dev/null && print_info "Added $SERVICE_USER to $group group" || true
fi
fi
done
fi
print_section "Step 2: Creating Installation Directories"
@@ -435,6 +458,11 @@ else
echo " • Run as user '$SERVICE_USER' for security"
echo " • Log to systemd journal (view with journalctl)"
echo ""
print_info "Serial port access:"
echo " • User '$SERVICE_USER' has been added to dialout group for serial port access"
echo " • If using serial connection, ensure the service is restarted after installation"
echo " • Group membership changes take effect after service restart"
echo ""
print_info "After editing config.ini, restart the service for changes to take effect:"
echo " ${YELLOW}sudo systemctl restart $SERVICE_NAME${NC}"
fi

View File

@@ -14,7 +14,10 @@ class HackerCommand(BaseCommand):
# Plugin metadata
name = "hacker"
keywords = ['sudo', 'ps aux', 'grep', 'ls -l', 'ls -la', 'echo $PATH']
keywords = ['sudo', 'ps aux', 'grep', 'ls -l', 'ls -la', 'echo $PATH', 'rm', 'rm -rf',
'cat', 'whoami', 'top', 'htop', 'netstat', 'ss', 'kill', 'killall', 'chmod',
'find', 'history', 'passwd', 'su', 'ssh', 'wget', 'curl', 'df -h', 'free',
'ifconfig', 'ip addr', 'uname -a']
description = "Simulates hacking a supervillain's mainframe with hilarious error messages"
category = "fun"
@@ -89,15 +92,15 @@ class HackerCommand(BaseCommand):
# grep command errors
elif command_lower.startswith('grep'):
fallback = [
"🔍 SEARCH FAILED: The One Ring has corrupted the search index. My precious...",
"📝 PATTERN NOT FOUND: The search database has been deleted by the evil AI.",
"🔍 SEARCH FAILED: The One Ring has corrupted the file search. My precious...",
"📝 PATTERN NOT FOUND: The search pattern has been blocked by the evil AI.",
"🎯 MISS: Your search pattern has been shot down by Imperial TIE fighters.",
"🧩 PUZZLE ERROR: The search results have been scattered by the Riddler.",
"💻 DATABASE CORRUPTED: The supervillain's search engine has crashed.",
"💻 FILE SYSTEM CORRUPTED: The supervillain's file system has crashed.",
"🎮 GAME OVER: The search has been defeated by the final boss.",
"🖥️ SEARCH ENGINE DOWN: Google has been hacked by the Dark Web.",
"🔐 ENCRYPTED RESULTS: The search results have been locked by ransomware.",
"🌐 NETWORK TIMEOUT: The search request got lost in cyberspace.",
"🖥️ SEARCH BLOCKED: File access has been blocked by the Dark Web.",
"🔐 ENCRYPTED FILES: The files are encrypted and cannot be searched.",
"🌐 READ TIMEOUT: The file read request got lost in cyberspace.",
"⚡ SEARCH FAILED: The pattern matching algorithm has been fried by a power surge."
]
return get_random_error('commands.hacker.grep_errors', fallback)
@@ -134,6 +137,292 @@ class HackerCommand(BaseCommand):
]
return get_random_error('commands.hacker.echo_path_errors', fallback)
# rm and rm -rf command errors (dangerous deletion!)
elif command_lower.startswith('rm -rf') or command_lower.startswith('rm -r'):
fallback = [
"💣 DESTRUCTION BLOCKED: The Death Star's safety protocols have prevented mass deletion!",
"🚨 EMERGENCY STOP: Dr. Evil has activated the emergency brake on file destruction.",
"🛡️ PROTECTION MODE: The Matrix has locked all files in read-only mode. No deletion allowed.",
"🔒 FILES LOCKED: Lex Luthor's mainframe has frozen all deletion commands.",
"⚡ POWER FAILURE: The supervillain's delete command has been short-circuited.",
"🎮 GAME SAVE PROTECTED: The final boss has enabled file protection mode.",
"🖥️ DELETION DENIED: The evil AI refuses to delete its own files.",
"🔐 ENCRYPTED FILES: All files are encrypted and cannot be deleted.",
"🌐 CLOUD SYNC: Files are syncing to the Matrix cloud. Deletion pending...",
"💀 SYSTEM REJECTION: The mainframe has rejected your deletion request. Files are too precious."
]
return get_random_error('commands.hacker.rm_errors', fallback)
elif command_lower.startswith('rm'):
fallback = [
"🗑️ DELETE FAILED: The supervillain's recycle bin is full and rejecting deletions.",
"🚫 REMOVAL BLOCKED: The Dark Overlord has protected all files from deletion.",
"💻 FILE LOCKED: The file system has been locked by the evil corporation.",
"🔒 PERMISSION DENIED: You don't have permission to delete files on the Death Star.",
"⚡ DELETION ERROR: The file deletion command has been corrupted by malware.",
"🎮 GAME OVER: The file you're trying to delete is the final boss's save file.",
"🖥️ SYSTEM ERROR: The delete command has crashed the file manager.",
"🔐 FILES PROTECTED: All files are protected by the supervillain's antivirus.",
"🌐 NETWORK ERROR: The deletion request got lost in cyberspace.",
"💀 FILE GHOST: The file has become a digital ghost and cannot be deleted."
]
return get_random_error('commands.hacker.rm_errors', fallback)
# cat command errors
elif command_lower.startswith('cat'):
fallback = [
"📄 FILE READ ERROR: The file has been encrypted by the Riddler's cipher.",
"📖 DOCUMENT CORRUPTED: The file contents have been scrambled by malware.",
"📚 ACCESS DENIED: The supervillain has classified this file as top secret.",
"🔍 FILE NOT FOUND: The file has been hidden by the Invisible Man.",
"💻 READ PERMISSION DENIED: The Matrix has locked this file from reading.",
"🎮 GAME FILE: This file belongs to the final boss and cannot be viewed.",
"🖥️ FILE SYSTEM ERROR: The file reader has crashed due to a virus.",
"🔐 ENCRYPTED FILE: The file contents are encrypted with ransomware.",
"🌐 CLOUD FILE: The file is stuck in the Matrix's cloud and cannot be read.",
"💀 FILE GHOST: The file exists but its contents have been deleted by digital ghosts."
]
return get_random_error('commands.hacker.cat_errors', fallback)
# whoami command errors
elif command_lower.startswith('whoami'):
fallback = [
"👤 IDENTITY ERROR: The Matrix has erased your identity. You are nobody.",
"🕵️ SPY DETECTED: The supervillain's system has detected an unknown user.",
"🎭 IDENTITY THEFT: Your identity has been stolen by the Riddler.",
"👻 GHOST USER: You are a digital ghost with no identity.",
"🔒 CLASSIFIED: Your identity is classified by the evil corporation.",
"🎮 GAME OVER: The final boss has deleted your player profile.",
"🖥️ USER DATABASE CORRUPTED: The user identity system has crashed.",
"🔐 IDENTITY ENCRYPTED: Your identity has been encrypted by ransomware.",
"🌐 IDENTITY LOST: Your identity got lost in the Matrix's network.",
"💀 USER DELETED: The Dark Overlord has deleted your user account."
]
return get_random_error('commands.hacker.whoami_errors', fallback)
# top and htop command errors
elif command_lower.startswith('htop') or command_lower.startswith('top'):
fallback = [
"📊 MONITOR ERROR: The process monitor has been hijacked by the Borg Collective.",
"⚙️ SYSTEM OVERLOAD: The Death Star's reactor is overheating. Monitor offline.",
"🤖 PROCESS HIDDEN: All processes have been hidden by the evil AI.",
"💻 MONITOR CRASHED: The system monitor has crashed due to a kernel panic.",
"🎮 GAME PAUSED: The final boss has paused all processes.",
"🖥️ BLUE SCREEN: The monitor has encountered a fatal error.",
"🔐 MONITOR ENCRYPTED: The process monitor has been locked by ransomware.",
"🌐 SYSTEM DISCONNECTED: The monitor cannot access the process table.",
"⚡ POWER SURGE: The monitor has been fried by a power surge.",
"💀 SYSTEM DEAD: The mainframe is dead. No processes to monitor."
]
return get_random_error('commands.hacker.top_errors', fallback)
# netstat and ss command errors
elif command_lower.startswith('netstat') or command_lower.startswith('ss '):
fallback = [
"🌐 NETWORK SCAN BLOCKED: The supervillain's firewall has blocked all network queries.",
"🔍 CONNECTION LIST CORRUPTED: The network connection table has been hacked by malware.",
"📡 SIGNAL JAMMED: Imperial TIE fighters are jamming all network signals.",
"💻 NETWORK DOWN: The Death Star's network stack has been destroyed.",
"🎮 GAME OVER: All network connections have been terminated by the final boss.",
"🖥️ NETWORK ERROR: The network stack has crashed due to a virus.",
"🔐 CONNECTIONS HIDDEN: All network connections have been encrypted and hidden.",
"🌐 MATRIX DISCONNECTED: The network routing table is stuck in the Matrix's void.",
"⚡ NETWORK FRIED: The network interface has been zapped by a power surge.",
"💀 NO CONNECTIONS: The mainframe has no active network connections. It's dead, Jim."
]
return get_random_error('commands.hacker.netstat_errors', fallback)
# kill and killall command errors
elif command_lower.startswith('killall') or command_lower.startswith('kill'):
fallback = [
"💀 KILL DENIED: The supervillain's processes are immortal and cannot be killed.",
"🚫 TERMINATION BLOCKED: The Dark Overlord has protected all processes from termination.",
"🛡️ PROCESS PROTECTED: The Matrix has locked all processes in protected mode.",
"🔒 KILL PERMISSION DENIED: You don't have permission to kill processes on the Death Star.",
"⚡ TERMINATION ERROR: The kill command has been corrupted by malware.",
"🎮 GAME OVER: The process you're trying to kill is the final boss. It's invincible.",
"🖥️ SYSTEM ERROR: The kill signal has been blocked by the kernel.",
"🔐 PROCESSES PROTECTED: All processes are protected and cannot be terminated.",
"🌐 KILL REQUEST LOST: The termination signal got lost in cyberspace.",
"💀 PROCESS GHOST: The process has become a zombie process and cannot be killed."
]
return get_random_error('commands.hacker.kill_errors', fallback)
# chmod command errors
elif command_lower.startswith('chmod'):
fallback = [
"🔐 PERMISSION DENIED: The supervillain has locked all file permissions.",
"🚫 CHMOD BLOCKED: The Dark Overlord refuses to allow permission changes.",
"🛡️ PERMISSIONS PROTECTED: The Matrix has frozen all file permissions.",
"🔒 PERMISSION ERROR: You don't have permission to change permissions. How meta!",
"⚡ CHMOD CORRUPTED: The permission change command has been fried by malware.",
"🎮 GAME OVER: The final boss has locked all file permissions.",
"🖥️ SYSTEM ERROR: The permission system has crashed due to a virus.",
"🔐 PERMISSIONS ENCRYPTED: All permissions are encrypted and cannot be changed.",
"🌐 PERMISSION REQUEST LOST: The permission change got lost in the Matrix.",
"💀 PERMISSIONS DEAD: The permission system is dead. No changes allowed."
]
return get_random_error('commands.hacker.chmod_errors', fallback)
# find command errors
elif command_lower.startswith('find'):
fallback = [
"🔍 SEARCH FAILED: The file search has been blocked by the supervillain's firewall.",
"📁 FILES HIDDEN: All files have been hidden by the Invisible Man's cloak.",
"💻 SEARCH CORRUPTED: The find command has been corrupted by malware.",
"🎯 TARGET NOT FOUND: The files you're searching for have been deleted by the evil AI.",
"🎮 GAME OVER: The final boss has hidden all files in another dimension.",
"🖥️ SEARCH ENGINE DOWN: The file search system has crashed.",
"🔐 FILES ENCRYPTED: All files are encrypted and cannot be found.",
"🌐 SEARCH LOST: The search request got lost in the Matrix's void.",
"⚡ SEARCH FRIED: The file search algorithm has been zapped by a power surge.",
"💀 NO FILES: The mainframe has no files. They've all been deleted."
]
return get_random_error('commands.hacker.find_errors', fallback)
# history command errors
elif command_lower.startswith('history'):
fallback = [
"📜 HISTORY ERASED: The supervillain has deleted all command history.",
"🕰️ TIME TRAVEL ERROR: The command history has been lost in a time paradox.",
"💻 HISTORY CORRUPTED: The history database has been hacked by malware.",
"🔒 ACCESS DENIED: The Dark Overlord has classified your command history as top secret.",
"🎮 GAME OVER: The final boss has reset your command history.",
"🖥️ HISTORY SYSTEM DOWN: The command history system has crashed.",
"🔐 HISTORY ENCRYPTED: Your command history has been encrypted by ransomware.",
"🌐 HISTORY LOST: Your command history got lost in the Matrix's network.",
"⚡ HISTORY FRIED: The history database has been zapped by a power surge.",
"💀 NO HISTORY: You have no command history. You are a blank slate."
]
return get_random_error('commands.hacker.history_errors', fallback)
# passwd command errors
elif command_lower.startswith('passwd'):
fallback = [
"🔐 PASSWORD CHANGE DENIED: The supervillain has locked all password changes.",
"🚫 PASSWORD BLOCKED: The Dark Overlord refuses to allow password modifications.",
"🛡️ PASSWORD PROTECTED: The Matrix has frozen all password changes.",
"🔒 PERMISSION DENIED: You don't have permission to change passwords on the Death Star.",
"⚡ PASSWORD ERROR: The password change command has been corrupted by malware.",
"🎮 GAME OVER: The final boss has locked all passwords.",
"🖥️ SYSTEM ERROR: The password system has crashed due to a virus.",
"🔐 PASSWORDS ENCRYPTED: All passwords are encrypted and cannot be changed.",
"🌐 PASSWORD REQUEST LOST: The password change got lost in the Matrix.",
"💀 PASSWORD SYSTEM DEAD: The password system is dead. No changes allowed."
]
return get_random_error('commands.hacker.passwd_errors', fallback)
# su command errors
elif command_lower.startswith('su '):
fallback = [
"🔄 SWITCH USER DENIED: The supervillain has blocked all user switching attempts.",
"🚫 USER SWITCH BLOCKED: The Dark Overlord refuses to allow user changes.",
"🛡️ USER PROTECTED: The Matrix has locked all user accounts.",
"🔒 PERMISSION DENIED: You don't have permission to switch users on the Death Star.",
"⚡ USER SWITCH ERROR: The su command has been corrupted by malware.",
"🎮 GAME OVER: The final boss has locked all user accounts.",
"🖥️ SYSTEM ERROR: The user system has crashed due to a virus.",
"🔐 USERS ENCRYPTED: All user accounts are encrypted and cannot be accessed.",
"🌐 USER REQUEST LOST: The user switch request got lost in the Matrix.",
"💀 USER SYSTEM DEAD: The user system is dead. No switching allowed."
]
return get_random_error('commands.hacker.su_errors', fallback)
# ssh command errors
elif command_lower.startswith('ssh'):
fallback = [
"🔌 SSH CONNECTION FAILED: The supervillain's server has blocked all SSH attempts.",
"🚫 REMOTE ACCESS DENIED: The Dark Overlord has closed all SSH ports.",
"🛡️ CONNECTION PROTECTED: The Matrix has locked all SSH connections.",
"🔒 SSH BLOCKED: The Death Star's firewall is blocking all SSH connections.",
"⚡ CONNECTION ERROR: The SSH handshake has been corrupted by malware.",
"🎮 GAME OVER: The final boss has disabled all remote access.",
"🖥️ SYSTEM ERROR: The SSH daemon has crashed due to a virus.",
"🔐 SSH DISABLED: All SSH connections have been disabled and blocked.",
"🌐 CONNECTION LOST: The SSH connection got lost in the Matrix's void.",
"💀 SSH DEAD: The SSH daemon is dead. No remote access allowed."
]
return get_random_error('commands.hacker.ssh_errors', fallback)
# wget and curl command errors
elif command_lower.startswith('wget') or command_lower.startswith('curl'):
fallback = [
"📥 DOWNLOAD BLOCKED: The supervillain's firewall has blocked all HTTP requests.",
"🚫 DOWNLOAD DENIED: The Dark Overlord refuses to allow file downloads.",
"🛡️ DOWNLOAD PROTECTED: The Matrix has locked all download capabilities.",
"🔒 DOWNLOAD BLOCKED: The Death Star's network is blocking all outbound connections.",
"⚡ DOWNLOAD ERROR: The HTTP request has been corrupted by malware.",
"🎮 GAME OVER: The final boss has disabled all downloads.",
"🖥️ SYSTEM ERROR: The network stack has crashed due to a virus.",
"🔐 DNS RESOLUTION FAILED: All domain names have been encrypted and blocked.",
"🌐 CONNECTION TIMEOUT: The download request got lost in the Matrix's network.",
"💀 DOWNLOAD DEAD: The network interface is dead. No downloads allowed."
]
return get_random_error('commands.hacker.download_errors', fallback)
# df -h command errors
elif command_lower.startswith('df -h') or command_lower.startswith('df'):
fallback = [
"💾 DISK SPACE ERROR: The supervillain's file system has been corrupted by malware.",
"📊 STORAGE SCAN FAILED: The disk space query has been hijacked by the Borg.",
"💻 DISK CORRUPTED: The file system has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all disk space information.",
"🖥️ SYSTEM ERROR: The file system mount table has crashed.",
"🔐 STORAGE ENCRYPTED: All file system information has been encrypted.",
"🌐 MOUNT FAILED: The disk mount information got lost in the Matrix's cloud.",
"⚡ STORAGE FRIED: The disk controller has been zapped by a power surge.",
"💀 NO STORAGE: The mainframe has no mounted file systems. It's all been deleted.",
"🗄️ FILESYSTEM CORRUPTED: The file system superblock has been corrupted by ransomware."
]
return get_random_error('commands.hacker.df_errors', fallback)
# free command errors
elif command_lower.startswith('free'):
fallback = [
"🧠 MEMORY ERROR: The supervillain's RAM has been corrupted by malware.",
"📊 MEMORY SCAN FAILED: The memory query has been hijacked by the Cybermen.",
"💻 MEMORY CORRUPTED: The RAM has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all memory information.",
"🖥️ SYSTEM ERROR: The memory management system has crashed.",
"🔐 MEMORY ENCRYPTED: All memory information has been encrypted.",
"🌐 MEMORY LOST: The memory statistics got lost in the Matrix's void.",
"⚡ MEMORY FRIED: The memory controller has been zapped by a power surge.",
"💀 NO MEMORY: The mainframe has no accessible memory. It's all been wiped.",
"🧩 MEMORY CORRUPTED: The memory mapping has been corrupted by ransomware."
]
return get_random_error('commands.hacker.free_errors', fallback)
# ifconfig and ip addr command errors
elif command_lower.startswith('ifconfig') or command_lower.startswith('ip addr'):
fallback = [
"🌐 NETWORK INTERFACE ERROR: The supervillain's network interfaces have been corrupted.",
"📡 INTERFACE SCAN FAILED: The network interface query has been hijacked by Imperial forces.",
"💻 INTERFACE CORRUPTED: The network interface configuration has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all network interface information.",
"🖥️ SYSTEM ERROR: The network interface driver has crashed.",
"🔐 INTERFACES ENCRYPTED: All network interface information has been encrypted.",
"🌐 INTERFACES LOST: The network interface data got lost in the Matrix's network.",
"⚡ INTERFACES FRIED: The network interface hardware has been zapped by a power surge.",
"💀 NO INTERFACES: The mainframe has no network interfaces. They've all been disabled.",
"🔌 CONNECTION BROKEN: All network interfaces have been disconnected by the Dark Overlord."
]
return get_random_error('commands.hacker.ifconfig_errors', fallback)
# uname -a command errors
elif command_lower.startswith('uname'):
fallback = [
"🖥️ SYSTEM INFO ERROR: The supervillain has classified all system information as top secret.",
"📊 INFO SCAN FAILED: The system information query has been hidden by the Invisible Man.",
"💻 SYSTEM CORRUPTED: The kernel version information has been destroyed by malware.",
"🎮 GAME OVER: The final boss has deleted all system information.",
"🖥️ SYSTEM ERROR: The kernel information system has crashed. How meta!",
"🔐 SYSTEM ENCRYPTED: All system information has been encrypted by ransomware.",
"🌐 SYSTEM LOST: The kernel version got lost in the Matrix's void.",
"⚡ SYSTEM FRIED: The system call interface has been zapped by a power surge.",
"💀 NO SYSTEM: The mainframe has no kernel information. It's a mystery.",
"🦹‍♂️ CLASSIFIED: Lex Luthor has classified all system information. Access denied."
]
return get_random_error('commands.hacker.uname_errors', fallback)
# Generic hacker error for other commands
else:
fallback = [
@@ -161,10 +450,14 @@ class HackerCommand(BaseCommand):
content_lower = content.lower()
# Commands that should match exactly (no arguments)
exact_match_commands = ['ls -l', 'ls -la', 'echo $PATH']
exact_match_commands = ['ls -l', 'ls -la', 'echo $PATH', 'df -h', 'whoami', 'history',
'top', 'htop', 'free', 'uname -a']
# Commands that should match as prefixes (can have arguments)
prefix_match_commands = ['sudo', 'ps aux', 'grep']
# Note: Longer prefixes must come first (e.g., 'rm -rf' before 'rm')
prefix_match_commands = ['sudo', 'ps aux', 'grep', 'rm -rf', 'rm -r', 'rm', 'cat',
'netstat', 'ss', 'killall', 'kill', 'chmod', 'find', 'passwd',
'su', 'ssh', 'wget', 'curl', 'df', 'ifconfig', 'ip addr', 'uname']
# Check for exact matches first
for keyword in exact_match_commands:

View File

@@ -532,15 +532,15 @@
"⚡ POWER SURGE: The supervillain's server farm has fried all running processes."
],
"grep_errors": [
"🔍 SEARCH FAILED: The One Ring has corrupted the search index. My precious...",
"📝 PATTERN NOT FOUND: The search database has been deleted by the evil AI.",
"🔍 SEARCH FAILED: The One Ring has corrupted the file search. My precious...",
"📝 PATTERN NOT FOUND: The search pattern has been blocked by the evil AI.",
"🎯 MISS: Your search pattern has been shot down by Imperial TIE fighters.",
"🧩 PUZZLE ERROR: The search results have been scattered by the Riddler.",
"💻 DATABASE CORRUPTED: The supervillain's search engine has crashed.",
"💻 FILE SYSTEM CORRUPTED: The supervillain's file system has crashed.",
"🎮 GAME OVER: The search has been defeated by the final boss.",
"🖥️ SEARCH ENGINE DOWN: Google has been hacked by the Dark Web.",
"🔐 ENCRYPTED RESULTS: The search results have been locked by ransomware.",
"🌐 NETWORK TIMEOUT: The search request got lost in cyberspace.",
"🖥️ SEARCH BLOCKED: File access has been blocked by the Dark Web.",
"🔐 ENCRYPTED FILES: The files are encrypted and cannot be searched.",
"🌐 READ TIMEOUT: The file read request got lost in cyberspace.",
"⚡ SEARCH FAILED: The pattern matching algorithm has been fried by a power surge."
],
"ls_errors": [
@@ -567,6 +567,210 @@
"🌐 NETWORK PATH DOWN: The directory paths are stuck in the Matrix's network.",
"⚡ PATH FRIED: The system paths have been zapped by a power surge."
],
"rm_errors": [
"💣 DESTRUCTION BLOCKED: The Death Star's safety protocols have prevented mass deletion!",
"🚨 EMERGENCY STOP: Dr. Evil has activated the emergency brake on file destruction.",
"🛡️ PROTECTION MODE: The Matrix has locked all files in read-only mode. No deletion allowed.",
"🔒 FILES LOCKED: Lex Luthor's mainframe has frozen all deletion commands.",
"⚡ POWER FAILURE: The supervillain's delete command has been short-circuited.",
"🎮 GAME SAVE PROTECTED: The final boss has enabled file protection mode.",
"🖥️ DELETION DENIED: The evil AI refuses to delete its own files.",
"🔐 ENCRYPTED FILES: All files are encrypted and cannot be deleted.",
"🌐 CLOUD SYNC: Files are syncing to the Matrix cloud. Deletion pending...",
"💀 SYSTEM REJECTION: The mainframe has rejected your deletion request. Files are too precious."
],
"cat_errors": [
"📄 FILE READ ERROR: The file has been encrypted by the Riddler's cipher.",
"📖 DOCUMENT CORRUPTED: The file contents have been scrambled by malware.",
"📚 ACCESS DENIED: The supervillain has classified this file as top secret.",
"🔍 FILE NOT FOUND: The file has been hidden by the Invisible Man.",
"💻 READ PERMISSION DENIED: The Matrix has locked this file from reading.",
"🎮 GAME FILE: This file belongs to the final boss and cannot be viewed.",
"🖥️ FILE SYSTEM ERROR: The file reader has crashed due to a virus.",
"🔐 ENCRYPTED FILE: The file contents are encrypted with ransomware.",
"🌐 CLOUD FILE: The file is stuck in the Matrix's cloud and cannot be read.",
"💀 FILE GHOST: The file exists but its contents have been deleted by digital ghosts."
],
"whoami_errors": [
"👤 IDENTITY ERROR: The Matrix has erased your identity. You are nobody.",
"🕵️ SPY DETECTED: The supervillain's system has detected an unknown user.",
"🎭 IDENTITY THEFT: Your identity has been stolen by the Riddler.",
"👻 GHOST USER: You are a digital ghost with no identity.",
"🔒 CLASSIFIED: Your identity is classified by the evil corporation.",
"🎮 GAME OVER: The final boss has deleted your player profile.",
"🖥️ USER DATABASE CORRUPTED: The user identity system has crashed.",
"🔐 IDENTITY ENCRYPTED: Your identity has been encrypted by ransomware.",
"🌐 IDENTITY LOST: Your identity got lost in the Matrix's network.",
"💀 USER DELETED: The Dark Overlord has deleted your user account."
],
"top_errors": [
"📊 MONITOR ERROR: The process monitor has been hijacked by the Borg Collective.",
"⚙️ SYSTEM OVERLOAD: The Death Star's reactor is overheating. Monitor offline.",
"🤖 PROCESS HIDDEN: All processes have been hidden by the evil AI.",
"💻 MONITOR CRASHED: The system monitor has crashed due to a kernel panic.",
"🎮 GAME PAUSED: The final boss has paused all processes.",
"🖥️ BLUE SCREEN: The monitor has encountered a fatal error.",
"🔐 MONITOR ENCRYPTED: The process monitor has been locked by ransomware.",
"🌐 SYSTEM DISCONNECTED: The monitor cannot access the process table.",
"⚡ POWER SURGE: The monitor has been fried by a power surge.",
"💀 SYSTEM DEAD: The mainframe is dead. No processes to monitor."
],
"netstat_errors": [
"🌐 NETWORK SCAN BLOCKED: The supervillain's firewall has blocked all network queries.",
"🔍 CONNECTION LIST CORRUPTED: The network connection table has been hacked by malware.",
"📡 SIGNAL JAMMED: Imperial TIE fighters are jamming all network signals.",
"💻 NETWORK DOWN: The Death Star's network stack has been destroyed.",
"🎮 GAME OVER: All network connections have been terminated by the final boss.",
"🖥️ NETWORK ERROR: The network stack has crashed due to a virus.",
"🔐 CONNECTIONS HIDDEN: All network connections have been encrypted and hidden.",
"🌐 MATRIX DISCONNECTED: The network routing table is stuck in the Matrix's void.",
"⚡ NETWORK FRIED: The network interface has been zapped by a power surge.",
"💀 NO CONNECTIONS: The mainframe has no active network connections. It's dead, Jim."
],
"kill_errors": [
"💀 KILL DENIED: The supervillain's processes are immortal and cannot be killed.",
"🚫 TERMINATION BLOCKED: The Dark Overlord has protected all processes from termination.",
"🛡️ PROCESS PROTECTED: The Matrix has locked all processes in protected mode.",
"🔒 KILL PERMISSION DENIED: You don't have permission to kill processes on the Death Star.",
"⚡ TERMINATION ERROR: The kill command has been corrupted by malware.",
"🎮 GAME OVER: The process you're trying to kill is the final boss. It's invincible.",
"🖥️ SYSTEM ERROR: The kill signal has been blocked by the kernel.",
"🔐 PROCESSES PROTECTED: All processes are protected and cannot be terminated.",
"🌐 KILL REQUEST LOST: The termination signal got lost in cyberspace.",
"💀 PROCESS GHOST: The process has become a zombie process and cannot be killed."
],
"chmod_errors": [
"🔐 PERMISSION DENIED: The supervillain has locked all file permissions.",
"🚫 CHMOD BLOCKED: The Dark Overlord refuses to allow permission changes.",
"🛡️ PERMISSIONS PROTECTED: The Matrix has frozen all file permissions.",
"🔒 PERMISSION ERROR: You don't have permission to change permissions. How meta!",
"⚡ CHMOD CORRUPTED: The permission change command has been fried by malware.",
"🎮 GAME OVER: The final boss has locked all file permissions.",
"🖥️ SYSTEM ERROR: The permission system has crashed due to a virus.",
"🔐 PERMISSIONS ENCRYPTED: All permissions are encrypted and cannot be changed.",
"🌐 PERMISSION REQUEST LOST: The permission change got lost in the Matrix.",
"💀 PERMISSIONS DEAD: The permission system is dead. No changes allowed."
],
"find_errors": [
"🔍 SEARCH FAILED: The file search has been blocked by the supervillain's firewall.",
"📁 FILES HIDDEN: All files have been hidden by the Invisible Man's cloak.",
"💻 SEARCH CORRUPTED: The find command has been corrupted by malware.",
"🎯 TARGET NOT FOUND: The files you're searching for have been deleted by the evil AI.",
"🎮 GAME OVER: The final boss has hidden all files in another dimension.",
"🖥️ SEARCH ENGINE DOWN: The file search system has crashed.",
"🔐 FILES ENCRYPTED: All files are encrypted and cannot be found.",
"🌐 SEARCH LOST: The search request got lost in the Matrix's void.",
"⚡ SEARCH FRIED: The file search algorithm has been zapped by a power surge.",
"💀 NO FILES: The mainframe has no files. They've all been deleted."
],
"history_errors": [
"📜 HISTORY ERASED: The supervillain has deleted all command history.",
"🕰️ TIME TRAVEL ERROR: The command history has been lost in a time paradox.",
"💻 HISTORY CORRUPTED: The history database has been hacked by malware.",
"🔒 ACCESS DENIED: The Dark Overlord has classified your command history as top secret.",
"🎮 GAME OVER: The final boss has reset your command history.",
"🖥️ HISTORY SYSTEM DOWN: The command history system has crashed.",
"🔐 HISTORY ENCRYPTED: Your command history has been encrypted by ransomware.",
"🌐 HISTORY LOST: Your command history got lost in the Matrix's network.",
"⚡ HISTORY FRIED: The history database has been zapped by a power surge.",
"💀 NO HISTORY: You have no command history. You are a blank slate."
],
"passwd_errors": [
"🔐 PASSWORD CHANGE DENIED: The supervillain has locked all password changes.",
"🚫 PASSWORD BLOCKED: The Dark Overlord refuses to allow password modifications.",
"🛡️ PASSWORD PROTECTED: The Matrix has frozen all password changes.",
"🔒 PERMISSION DENIED: You don't have permission to change passwords on the Death Star.",
"⚡ PASSWORD ERROR: The password change command has been corrupted by malware.",
"🎮 GAME OVER: The final boss has locked all passwords.",
"🖥️ SYSTEM ERROR: The password system has crashed due to a virus.",
"🔐 PASSWORDS ENCRYPTED: All passwords are encrypted and cannot be changed.",
"🌐 PASSWORD REQUEST LOST: The password change got lost in the Matrix.",
"💀 PASSWORD SYSTEM DEAD: The password system is dead. No changes allowed."
],
"su_errors": [
"🔄 SWITCH USER DENIED: The supervillain has blocked all user switching attempts.",
"🚫 USER SWITCH BLOCKED: The Dark Overlord refuses to allow user changes.",
"🛡️ USER PROTECTED: The Matrix has locked all user accounts.",
"🔒 PERMISSION DENIED: You don't have permission to switch users on the Death Star.",
"⚡ USER SWITCH ERROR: The su command has been corrupted by malware.",
"🎮 GAME OVER: The final boss has locked all user accounts.",
"🖥️ SYSTEM ERROR: The user system has crashed due to a virus.",
"🔐 USERS ENCRYPTED: All user accounts are encrypted and cannot be accessed.",
"🌐 USER REQUEST LOST: The user switch request got lost in the Matrix.",
"💀 USER SYSTEM DEAD: The user system is dead. No switching allowed."
],
"ssh_errors": [
"🔌 SSH CONNECTION FAILED: The supervillain's server has blocked all SSH attempts.",
"🚫 REMOTE ACCESS DENIED: The Dark Overlord has closed all SSH ports.",
"🛡️ CONNECTION PROTECTED: The Matrix has locked all SSH connections.",
"🔒 SSH BLOCKED: The Death Star's firewall is blocking all SSH connections.",
"⚡ CONNECTION ERROR: The SSH handshake has been corrupted by malware.",
"🎮 GAME OVER: The final boss has disabled all remote access.",
"🖥️ SYSTEM ERROR: The SSH daemon has crashed due to a virus.",
"🔐 SSH DISABLED: All SSH connections have been disabled and blocked.",
"🌐 CONNECTION LOST: The SSH connection got lost in the Matrix's void.",
"💀 SSH DEAD: The SSH daemon is dead. No remote access allowed."
],
"download_errors": [
"📥 DOWNLOAD BLOCKED: The supervillain's firewall has blocked all HTTP requests.",
"🚫 DOWNLOAD DENIED: The Dark Overlord refuses to allow file downloads.",
"🛡️ DOWNLOAD PROTECTED: The Matrix has locked all download capabilities.",
"🔒 DOWNLOAD BLOCKED: The Death Star's network is blocking all outbound connections.",
"⚡ DOWNLOAD ERROR: The HTTP request has been corrupted by malware.",
"🎮 GAME OVER: The final boss has disabled all downloads.",
"🖥️ SYSTEM ERROR: The network stack has crashed due to a virus.",
"🔐 DNS RESOLUTION FAILED: All domain names have been encrypted and blocked.",
"🌐 CONNECTION TIMEOUT: The download request got lost in the Matrix's network.",
"💀 DOWNLOAD DEAD: The network interface is dead. No downloads allowed."
],
"df_errors": [
"💾 DISK SPACE ERROR: The supervillain's file system has been corrupted by malware.",
"📊 STORAGE SCAN FAILED: The disk space query has been hijacked by the Borg.",
"💻 DISK CORRUPTED: The file system has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all disk space information.",
"🖥️ SYSTEM ERROR: The file system mount table has crashed.",
"🔐 STORAGE ENCRYPTED: All file system information has been encrypted.",
"🌐 MOUNT FAILED: The disk mount information got lost in the Matrix's cloud.",
"⚡ STORAGE FRIED: The disk controller has been zapped by a power surge.",
"💀 NO STORAGE: The mainframe has no mounted file systems. It's all been deleted.",
"🗄️ FILESYSTEM CORRUPTED: The file system superblock has been corrupted by ransomware."
],
"free_errors": [
"🧠 MEMORY ERROR: The supervillain's RAM has been corrupted by malware.",
"📊 MEMORY SCAN FAILED: The memory query has been hijacked by the Cybermen.",
"💻 MEMORY CORRUPTED: The RAM has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all memory information.",
"🖥️ SYSTEM ERROR: The memory management system has crashed.",
"🔐 MEMORY ENCRYPTED: All memory information has been encrypted.",
"🌐 MEMORY LOST: The memory statistics got lost in the Matrix's void.",
"⚡ MEMORY FRIED: The memory controller has been zapped by a power surge.",
"💀 NO MEMORY: The mainframe has no accessible memory. It's all been wiped.",
"🧩 MEMORY CORRUPTED: The memory mapping has been corrupted by ransomware."
],
"ifconfig_errors": [
"🌐 NETWORK INTERFACE ERROR: The supervillain's network interfaces have been corrupted.",
"📡 INTERFACE SCAN FAILED: The network interface query has been hijacked by Imperial forces.",
"💻 INTERFACE CORRUPTED: The network interface configuration has been destroyed by a virus.",
"🎮 GAME OVER: The final boss has deleted all network interface information.",
"🖥️ SYSTEM ERROR: The network interface driver has crashed.",
"🔐 INTERFACES ENCRYPTED: All network interface information has been encrypted.",
"🌐 INTERFACES LOST: The network interface data got lost in the Matrix's network.",
"⚡ INTERFACES FRIED: The network interface hardware has been zapped by a power surge.",
"💀 NO INTERFACES: The mainframe has no network interfaces. They've all been disabled.",
"🔌 CONNECTION BROKEN: All network interfaces have been disconnected by the Dark Overlord."
],
"uname_errors": [
"🖥️ SYSTEM INFO ERROR: The supervillain has classified all system information as top secret.",
"📊 INFO SCAN FAILED: The system information query has been hidden by the Invisible Man.",
"💻 SYSTEM CORRUPTED: The kernel version information has been destroyed by malware.",
"🎮 GAME OVER: The final boss has deleted all system information.",
"🖥️ SYSTEM ERROR: The kernel information system has crashed. How meta!",
"🔐 SYSTEM ENCRYPTED: All system information has been encrypted by ransomware.",
"🌐 SYSTEM LOST: The kernel version got lost in the Matrix's void.",
"⚡ SYSTEM FRIED: The system call interface has been zapped by a power surge.",
"💀 NO SYSTEM: The mainframe has no kernel information. It's a mystery.",
"🦹‍♂️ CLASSIFIED: Lex Luthor has classified all system information. Access denied."
],
"generic_errors": [
"💻 MAINFRAME ERROR: The supervillain's computer is having a bad day.",
"🤖 SYSTEM MALFUNCTION: The evil AI has gone on strike.",

View File

@@ -1,6 +1,12 @@
#!/bin/bash
# MeshCore Bot Service Uninstallation Script
# This script removes the MeshCore Bot systemd service
# This script removes the MeshCore Bot service (systemd or launchd)
# Supports both Linux (systemd) and macOS (launchd)
#
# Safety features:
# - Backs up config.ini before removal
# - Asks for confirmation before destructive actions
# - Optionally preserves installation files
set -e
@@ -9,89 +15,489 @@ RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Configuration
# Detect operating system
OS="$(uname -s)"
IS_MACOS=false
IS_LINUX=false
if [[ "$OS" == "Darwin" ]]; then
IS_MACOS=true
SERVICE_TYPE="launchd"
elif [[ "$OS" == "Linux" ]]; then
IS_LINUX=true
SERVICE_TYPE="systemd"
else
echo "Error: Unsupported operating system: $OS"
echo "This script supports Linux (systemd) and macOS (launchd)"
exit 1
fi
# Configuration - OS-specific paths
SERVICE_NAME="meshcore-bot"
SERVICE_USER="meshcore"
SERVICE_GROUP="meshcore"
INSTALL_DIR="/opt/meshcore-bot"
LOG_DIR="/var/log/meshcore-bot"
PLIST_NAME="com.meshcore.bot"
echo -e "${BLUE}MeshCore Bot Service Uninstaller${NC}"
echo "===================================="
if [[ "$IS_MACOS" == true ]]; then
SERVICE_USER="$(whoami)"
SERVICE_GROUP="staff"
INSTALL_DIR="/usr/local/meshcore-bot"
LOG_DIR="/usr/local/var/log/meshcore-bot"
SERVICE_FILE="com.meshcore.bot.plist"
LAUNCHD_DIR="/Library/LaunchDaemons"
else
SERVICE_USER="meshcore"
SERVICE_GROUP="meshcore"
INSTALL_DIR="/opt/meshcore-bot"
LOG_DIR="/var/log/meshcore-bot"
SERVICE_FILE="meshcore-bot.service"
SYSTEMD_DIR="/etc/systemd/system"
fi
# Check if running as root
# Capture original user before sudo (for backup location)
ORIGINAL_USER="${SUDO_USER:-$USER}"
if [[ -n "$ORIGINAL_USER" ]] && [[ "$ORIGINAL_USER" != "root" ]]; then
# Try to get home directory of original user
HOME_DIR=$(eval echo ~"$ORIGINAL_USER" 2>/dev/null || echo "/home/$ORIGINAL_USER")
# Verify it exists and is writable
if [[ ! -d "$HOME_DIR" ]] || [[ ! -w "$HOME_DIR" ]]; then
HOME_DIR="/tmp"
fi
else
# Fallback to /tmp if we can't determine user home
HOME_DIR="/tmp"
fi
# Function to print section headers
print_section() {
echo ""
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}
# Function to print info messages
print_info() {
echo -e "${CYAN}${NC} $1"
}
# Function to print success messages
print_success() {
echo -e "${GREEN}${NC} $1"
}
# Function to print warning messages
print_warning() {
echo -e "${YELLOW}${NC} $1"
}
# Function to print error messages
print_error() {
echo -e "${RED}${NC} $1"
}
# Function to ask yes/no question
ask_yes_no() {
local prompt="$1"
local default="${2:-n}" # Default to 'no' for safety
local response
if [[ "$default" == "y" ]]; then
prompt="${prompt} [Y/n]: "
else
prompt="${prompt} [y/N]: "
fi
while true; do
read -p "$(echo -e "${YELLOW}${prompt}${NC}")" response
response="${response:-$default}"
case "$response" in
[Yy]|[Yy][Ee][Ss])
return 0
;;
[Nn]|[Nn][Oo])
return 1
;;
*)
echo "Please answer yes or no."
;;
esac
done
}
print_section "MeshCore Bot Service Uninstaller"
echo ""
if [[ "$IS_MACOS" == true ]]; then
print_info "Detected macOS - will remove launchd service"
else
print_info "Detected Linux - will remove systemd service"
fi
print_warning "This script will remove the MeshCore Bot service"
echo ""
# Check if script has execute permissions
if [ ! -x "$0" ]; then
print_warning "Script does not have execute permissions. Attempting to set them..."
chmod +x "$0" 2>/dev/null || {
print_error "Could not set execute permissions. Please run: chmod +x uninstall-service.sh"
exit 1
}
print_success "Execute permissions set"
fi
# Check if running as root, if not re-execute with sudo
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root (use sudo)${NC}"
exit 1
print_warning "This script requires root privileges to remove system services"
print_info "Re-executing with sudo..."
echo ""
exec sudo "$0" "$@"
fi
echo -e "${YELLOW}Step 1: Stopping and disabling service${NC}"
# Stop service if running
if systemctl is-active --quiet "$SERVICE_NAME"; then
systemctl stop "$SERVICE_NAME"
echo -e "${GREEN}Stopped $SERVICE_NAME service${NC}"
# Check if service exists
SERVICE_EXISTS=false
if [[ "$IS_MACOS" == true ]]; then
if [ -f "$LAUNCHD_DIR/$SERVICE_FILE" ]; then
SERVICE_EXISTS=true
fi
else
echo -e "${YELLOW}Service $SERVICE_NAME is not running${NC}"
if [ -f "$SYSTEMD_DIR/$SERVICE_NAME.service" ]; then
SERVICE_EXISTS=true
fi
fi
# Disable service
if systemctl is-enabled --quiet "$SERVICE_NAME"; then
systemctl disable "$SERVICE_NAME"
echo -e "${GREEN}Disabled $SERVICE_NAME service${NC}"
else
echo -e "${YELLOW}Service $SERVICE_NAME is not enabled${NC}"
if [[ "$SERVICE_EXISTS" == false ]]; then
print_warning "Service not found - it may have already been removed"
if [[ "$IS_MACOS" == true ]]; then
print_info "Expected service file: $LAUNCHD_DIR/$SERVICE_FILE"
else
print_info "Expected service file: $SYSTEMD_DIR/$SERVICE_NAME.service"
fi
echo ""
if ! ask_yes_no "Continue anyway? (will only remove files if they exist)"; then
print_info "Uninstallation cancelled by user"
exit 0
fi
fi
echo -e "${YELLOW}Step 2: Removing systemd service file${NC}"
# Remove service file
if [ -f "/etc/systemd/system/$SERVICE_NAME.service" ]; then
rm "/etc/systemd/system/$SERVICE_NAME.service"
echo -e "${GREEN}Removed service file${NC}"
else
echo -e "${YELLOW}Service file not found${NC}"
fi
# Reload systemd
systemctl daemon-reload
echo -e "${GREEN}Reloaded systemd configuration${NC}"
echo -e "${YELLOW}Step 3: Removing installation directory${NC}"
# Remove installation directory
# Check if installation directory exists
INSTALL_EXISTS=false
if [ -d "$INSTALL_DIR" ]; then
rm -rf "$INSTALL_DIR"
echo -e "${GREEN}Removed installation directory: $INSTALL_DIR${NC}"
INSTALL_EXISTS=true
CONFIG_FILE="$INSTALL_DIR/config.ini"
else
echo -e "${YELLOW}Installation directory not found${NC}"
CONFIG_FILE=""
fi
echo -e "${YELLOW}Step 4: Removing log directory${NC}"
# Remove log directory
# Step 1: Backup config.ini if it exists
if [[ "$INSTALL_EXISTS" == true ]] && [ -f "$CONFIG_FILE" ]; then
print_section "Step 1: Backup Configuration File"
print_info "Found configuration file: $CONFIG_FILE"
if ask_yes_no "Would you like to backup config.ini?" "y"; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$HOME_DIR/meshcore-bot-config-backup-${TIMESTAMP}.ini"
# Create backup
cp "$CONFIG_FILE" "$BACKUP_FILE"
# Try to set ownership to original user if possible
if [[ -n "$ORIGINAL_USER" ]] && [[ "$ORIGINAL_USER" != "root" ]]; then
chown "$ORIGINAL_USER:$(id -gn "$ORIGINAL_USER" 2>/dev/null || echo 'staff')" "$BACKUP_FILE" 2>/dev/null || true
fi
print_success "Configuration backed up to: $BACKUP_FILE"
if [[ "$HOME_DIR" == "/tmp" ]]; then
print_info "Backup saved to /tmp (home directory not accessible)"
fi
else
print_info "Skipping config.ini backup"
fi
# Step 1b: Backup database file
print_section "Step 1b: Database Backup"
# Try to find the main database file (meshcore_bot.db by default, or from config)
MAIN_DB_FILE=""
# First, try to read db_path from config.ini if it exists
if [ -f "$CONFIG_FILE" ]; then
DB_PATH_FROM_CONFIG=$(grep -E "^db_path\s*=" "$CONFIG_FILE" 2>/dev/null | head -1 | cut -d'=' -f2 | tr -d ' ' || echo "")
if [ -n "$DB_PATH_FROM_CONFIG" ]; then
# If it's a relative path, make it relative to install dir
if [[ "$DB_PATH_FROM_CONFIG" != /* ]]; then
MAIN_DB_FILE="$INSTALL_DIR/$DB_PATH_FROM_CONFIG"
else
MAIN_DB_FILE="$DB_PATH_FROM_CONFIG"
fi
fi
fi
# If not found in config, try default location
if [ -z "$MAIN_DB_FILE" ] || [ ! -f "$MAIN_DB_FILE" ]; then
MAIN_DB_FILE="$INSTALL_DIR/meshcore_bot.db"
fi
# Check if main database file exists
if [ -f "$MAIN_DB_FILE" ]; then
db_name=$(basename "$MAIN_DB_FILE")
db_size=$(du -h "$MAIN_DB_FILE" 2>/dev/null | cut -f1)
print_info "Found database file: $db_name (${db_size})"
echo ""
if ask_yes_no "Would you like to backup the database file?" "y"; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$HOME_DIR/meshcore-bot-db-backup-${TIMESTAMP}.db"
cp "$MAIN_DB_FILE" "$BACKUP_FILE"
# Try to set ownership to original user if possible
if [[ -n "$ORIGINAL_USER" ]] && [[ "$ORIGINAL_USER" != "root" ]]; then
chown "$ORIGINAL_USER:$(id -gn "$ORIGINAL_USER" 2>/dev/null || echo 'staff')" "$BACKUP_FILE" 2>/dev/null || true
fi
print_success "Database backed up to: $BACKUP_FILE"
if [[ "$HOME_DIR" == "/tmp" ]]; then
print_info "Backup saved to /tmp (home directory not accessible)"
fi
else
print_info "Skipping database backup"
fi
else
print_warning "Database file not found: $MAIN_DB_FILE"
print_info "Skipping database backup"
fi
else
print_section "Step 1: Configuration and Database Files"
if [[ "$INSTALL_EXISTS" == false ]]; then
print_warning "Installation directory not found: $INSTALL_DIR"
else
print_warning "Configuration file not found: $CONFIG_FILE"
fi
print_info "Skipping backup step"
fi
# Step 2: Confirm service removal
print_section "Step 2: Service Removal Confirmation"
print_warning "This will stop and remove the MeshCore Bot service"
if [[ "$IS_MACOS" == true ]]; then
print_info "Service: $PLIST_NAME (launchd)"
else
print_info "Service: $SERVICE_NAME (systemd)"
fi
echo ""
if ! ask_yes_no "Do you want to remove the service?"; then
print_info "Service removal cancelled by user"
echo ""
if [[ "$INSTALL_EXISTS" == true ]]; then
print_info "Installation files remain at: $INSTALL_DIR"
print_info "You can remove them manually if needed"
fi
exit 0
fi
# Step 3: Stop and remove service
print_section "Step 3: Stopping and Removing Service"
if [[ "$IS_MACOS" == true ]]; then
# macOS: Unload launchd service
if launchctl list "$PLIST_NAME" &>/dev/null 2>&1; then
print_info "Stopping service..."
launchctl stop "$PLIST_NAME" 2>/dev/null || true
launchctl unload "$LAUNCHD_DIR/$SERVICE_FILE" 2>/dev/null || true
print_success "Service stopped and unloaded"
else
print_warning "Service is not currently loaded"
fi
# Remove plist file
if [ -f "$LAUNCHD_DIR/$SERVICE_FILE" ]; then
rm "$LAUNCHD_DIR/$SERVICE_FILE"
print_success "Removed service plist file"
else
print_warning "Service plist file not found"
fi
else
# Linux: Stop and disable systemd service
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
print_info "Stopping service..."
systemctl stop "$SERVICE_NAME"
print_success "Service stopped"
else
print_warning "Service is not currently running"
fi
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
print_info "Disabling service..."
systemctl disable "$SERVICE_NAME" >/dev/null 2>&1
print_success "Service disabled"
else
print_warning "Service is not enabled"
fi
# Remove service file
if [ -f "$SYSTEMD_DIR/$SERVICE_NAME.service" ]; then
rm "$SYSTEMD_DIR/$SERVICE_NAME.service"
print_success "Removed service file"
# Reload systemd
print_info "Reloading systemd configuration"
systemctl daemon-reload
print_success "Systemd configuration reloaded"
else
print_warning "Service file not found"
fi
fi
# Step 4: Ask about removing installation files
print_section "Step 4: Installation Files"
if [[ "$INSTALL_EXISTS" == true ]]; then
print_warning "Installation directory found: $INSTALL_DIR"
print_info "This contains all bot files, including:"
echo " • Python scripts and modules"
echo " • Configuration files"
echo " • Virtual environment"
echo " • Database files"
echo " • Logs"
echo ""
if ask_yes_no "Do you want to DELETE the installation directory and all its contents?"; then
print_warning "This action cannot be undone!"
if ask_yes_no "Are you SURE you want to delete $INSTALL_DIR?"; then
print_info "Removing installation directory..."
rm -rf "$INSTALL_DIR"
print_success "Removed installation directory: $INSTALL_DIR"
else
print_info "Installation directory preserved: $INSTALL_DIR"
fi
else
print_info "Installation directory preserved: $INSTALL_DIR"
print_info "You can remove it manually later if needed"
fi
else
print_warning "Installation directory not found: $INSTALL_DIR"
print_info "Nothing to remove"
fi
# Step 5: Remove log directory (optional)
print_section "Step 5: Log Directory"
if [ -d "$LOG_DIR" ]; then
rm -rf "$LOG_DIR"
echo -e "${GREEN}Removed log directory: $LOG_DIR${NC}"
print_info "Log directory found: $LOG_DIR"
if ask_yes_no "Do you want to remove the log directory?"; then
rm -rf "$LOG_DIR"
print_success "Removed log directory: $LOG_DIR"
else
print_info "Log directory preserved: $LOG_DIR"
fi
else
echo -e "${YELLOW}Log directory not found${NC}"
print_warning "Log directory not found: $LOG_DIR"
fi
echo -e "${YELLOW}Step 5: Removing service user${NC}"
# Remove service user
if id "$SERVICE_USER" &>/dev/null; then
userdel "$SERVICE_USER"
echo -e "${GREEN}Removed user: $SERVICE_USER${NC}"
# Step 6: Remove service user (Linux only)
if [[ "$IS_LINUX" == true ]]; then
print_section "Step 6: Service User"
if id "$SERVICE_USER" &>/dev/null; then
print_info "Service user found: $SERVICE_USER"
if ask_yes_no "Do you want to remove the service user '$SERVICE_USER'?"; then
userdel "$SERVICE_USER" 2>/dev/null || {
print_warning "Could not remove user (may be in use or have dependencies)"
}
print_success "Removed service user: $SERVICE_USER"
else
print_info "Service user preserved: $SERVICE_USER"
fi
else
print_warning "Service user not found: $SERVICE_USER"
fi
fi
# Final summary
print_section "Uninstallation Complete"
echo ""
print_success "Service uninstallation completed!"
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}📋 Summary${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
if [[ "$IS_MACOS" == true ]]; then
echo -e " ${CYAN}Service:${NC} Removed from launchd"
echo -e " ${CYAN}Service file:${NC} $LAUNCHD_DIR/$SERVICE_FILE (removed)"
else
echo -e "${YELLOW}User $SERVICE_USER not found${NC}"
echo -e " ${CYAN}Service:${NC} Removed from systemd"
echo -e " ${CYAN}Service file:${NC} $SYSTEMD_DIR/$SERVICE_NAME.service (removed)"
fi
if [[ "$INSTALL_EXISTS" == true ]]; then
if [ -d "$INSTALL_DIR" ]; then
echo -e " ${CYAN}Installation:${NC} ${YELLOW}Preserved at $INSTALL_DIR${NC}"
else
echo -e " ${CYAN}Installation:${NC} ${GREEN}Removed${NC}"
fi
else
echo -e " ${CYAN}Installation:${NC} Not found (may have been removed already)"
fi
if [ -d "$LOG_DIR" ]; then
echo -e " ${CYAN}Logs:${NC} ${YELLOW}Preserved at $LOG_DIR${NC}"
else
echo -e " ${CYAN}Logs:${NC} ${GREEN}Removed${NC}"
fi
if [[ "$IS_LINUX" == true ]]; then
if id "$SERVICE_USER" &>/dev/null; then
echo -e " ${CYAN}Service user:${NC} ${YELLOW}Preserved: $SERVICE_USER${NC}"
else
echo -e " ${CYAN}Service user:${NC} ${GREEN}Removed${NC}"
fi
fi
echo ""
echo -e "${GREEN}Uninstallation completed successfully!${NC}"
# Check for backup files in common locations
CONFIG_BACKUP_FOUND=$(find "$HOME_DIR" /tmp /home -name "meshcore-bot-config-backup-*.ini" -type f 2>/dev/null | head -1)
DB_BACKUP_FOUND=$(find "$HOME_DIR" /tmp /home -name "meshcore-bot-db-backup-*.db" -type f 2>/dev/null | head -1)
if [ -n "$CONFIG_BACKUP_FOUND" ] || [ -n "$DB_BACKUP_FOUND" ]; then
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}💾 Backup Files${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
if [ -n "$CONFIG_BACKUP_FOUND" ]; then
print_success "Configuration backup saved to:"
echo " ${YELLOW}$CONFIG_BACKUP_FOUND${NC}"
echo ""
fi
if [ -n "$DB_BACKUP_FOUND" ]; then
print_success "Database backup saved to:"
echo " ${YELLOW}$DB_BACKUP_FOUND${NC}"
echo ""
fi
print_info "You can restore these backups when reinstalling"
echo ""
fi
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE} Additional Notes${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e "${BLUE}What was removed:${NC}"
echo " - Systemd service file"
echo " - Installation directory: $INSTALL_DIR"
echo " - Log directory: $LOG_DIR"
echo " - Service user: $SERVICE_USER"
print_info "Python packages installed via pip are not automatically removed"
print_info "If you want to remove them, run:"
echo " ${YELLOW}pip3 uninstall -r requirements.txt${NC}"
echo ""
if [[ "$INSTALL_EXISTS" == true ]] && [ -d "$INSTALL_DIR" ]; then
print_warning "Installation files are still present at: $INSTALL_DIR"
print_info "You can remove them manually with:"
echo " ${YELLOW}sudo rm -rf $INSTALL_DIR${NC}"
echo ""
fi
print_success "Uninstallation process completed!"
echo ""
echo -e "${YELLOW}Note: Python packages installed via pip are not removed${NC}"
echo -e "${YELLOW}If you want to remove them, run: pip3 uninstall -r requirements.txt${NC}"