Created
December 29, 2024 22:15
-
-
Save TheNoiselessNoise/3c3746d6b21ae471db45b942a78a0b27 to your computer and use it in GitHub Desktop.
Linux - Fix permissions on accidental bad chown -R
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Color and style definitions | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| MAGENTA='\033[0;35m' | |
| CYAN='\033[0;36m' | |
| BOLD='\033[1m' | |
| NC='\033[0m' | |
| # Check if running as root | |
| if [ "$EUID" -ne 0 ]; then | |
| echo -e "${RED}${BOLD}Please run as root${NC}" | |
| exit 1 | |
| fi | |
| # Initialize log files | |
| LOG_DIR="/var/log/permission-fix" | |
| SUCCESS_LOG="${LOG_DIR}/success.log" | |
| ERROR_LOG="${LOG_DIR}/error.log" | |
| WARN_LOG="${LOG_DIR}/warning.log" | |
| mkdir -p "$LOG_DIR" | |
| date > "$SUCCESS_LOG" | |
| date > "$ERROR_LOG" | |
| date > "$WARN_LOG" | |
| # Logging functions | |
| log_success() { | |
| echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "$SUCCESS_LOG" | |
| } | |
| log_error() { | |
| echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "$ERROR_LOG" | |
| } | |
| log_warning() { | |
| echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "$WARN_LOG" | |
| } | |
| # Format functions | |
| format_path() { | |
| echo -e "${BLUE}${BOLD}$1${NC}" | |
| } | |
| format_perms() { | |
| echo -e "${MAGENTA}${BOLD}$1${NC}" | |
| } | |
| format_ownership() { | |
| echo -e "${CYAN}${BOLD}$1${NC}" | |
| } | |
| # Check functions | |
| user_exists() { | |
| id "$1" >/dev/null 2>&1 | |
| } | |
| group_exists() { | |
| getent group "$1" >/dev/null 2>&1 | |
| } | |
| # Define permissions and ownership in a hierarchical structure | |
| # Format: "path:owner:group:permissions:recursive" | |
| # permissions: optional octal format, e.g. 755 | |
| # example 1: "/var/log:root:adm:750:false" | |
| # example 2: "/var/log:root:adm::false | |
| declare -a PERMISSION_LIST=( | |
| # Base directories | |
| "/var:root:root:755:false" | |
| "/var/backups:root:root:755:false" | |
| "/var/cache:root:root:755:false" | |
| "/var/crash:root:root:755:false" | |
| "/var/lib:root:root:755:false" | |
| "/var/local:root:root:755:false" | |
| "/var/lock:root:root:755:false" | |
| "/var/log:root:root:755:false" | |
| "/var/mail:root:mail:2775:false" | |
| "/var/opt:root:root:755:false" | |
| "/var/run:root:root:755:false" | |
| "/var/spool:root:root:755:false" | |
| "/var/tmp:root:root:1777:false" | |
| # Special directories with recursive permissions | |
| # graphical desktop managers | |
| "/var/lib/gdm3:gdm:gdm::true" | |
| # Web servers | |
| "/var/www:www-data:www-data:755:true" | |
| "/var/log/apache2:www-data:adm:750:false" | |
| "/var/log/nginx:www-data:adm:750:false" | |
| # Databases | |
| "/var/lib/mysql:mysql:mysql:750:true" | |
| "/var/log/mysql:mysql:adm:750:false" | |
| "/var/run/mysqld:mysql:mysql:755:false" | |
| "/var/lib/postgresql:postgres:postgres:750:true" | |
| "/var/log/postgresql:postgres:adm:750:false" | |
| # Mail servers | |
| "/var/spool/postfix:postfix:postfix:750:true" | |
| "/var/log/mail:root:adm:750:false" | |
| # Print server | |
| "/var/spool/cups:root:lp:755:true" | |
| "/var/log/cups:root:lp:750:false" | |
| # SSH | |
| "/var/log/ssh:root:adm:750:false" | |
| # PHP-FPM | |
| "/var/log/php-fpm:www-data:adm:750:false" | |
| "/var/run/php-fpm:www-data:www-data:755:false" | |
| # System services | |
| "/var/lib/systemd:root:root:755:true" | |
| "/var/log/journal:root:systemd-journal:2755:false" | |
| # Container runtimes | |
| "/var/lib/docker:root:docker:710:false" | |
| "/var/run/docker.sock:root:docker:660:false" | |
| "/var/lib/containerd:root:root:711:false" | |
| "/var/lib/podman:root:root:700:false" | |
| # Package management | |
| "/var/cache/apt:root:root:755:false" | |
| "/var/lib/apt:root:root:755:false" | |
| ) | |
| # Optional mount point for Live USB recovery | |
| MOUNT_POINT="" | |
| if [ "$1" ]; then | |
| MOUNT_POINT="$1" | |
| echo -e "Using mount point: $(format_path "$MOUNT_POINT")" | |
| log_warning "Using custom mount point: $MOUNT_POINT" | |
| fi | |
| fix_permissions() { | |
| local entry=$1 | |
| IFS=':' read -r path owner group permissions recursive <<< "$entry" | |
| local full_path="${MOUNT_POINT}${path}" | |
| local success=true | |
| # Check if directory exists | |
| if [ ! -d "$full_path" ]; then | |
| log_error "Directory does not exist: $(format_path "$full_path")" | |
| return 1 | |
| fi | |
| # Validate owner and group | |
| if ! user_exists "$owner"; then | |
| log_error "User '$(format_ownership "$owner")' does not exist for $(format_path "$path")" | |
| return 1 | |
| fi | |
| if ! group_exists "$group"; then | |
| log_error "Group '$(format_ownership "$group")' does not exist for $(format_path "$path")" | |
| return 1 | |
| fi | |
| # Apply ownership | |
| local chown_cmd="chown" | |
| [ "$recursive" = "true" ] && chown_cmd="chown -R" | |
| if ! $chown_cmd "$owner:$group" "$full_path" 2>/dev/null; then | |
| log_error "Failed to set $([ "$recursive" = "true" ] && echo "recursive ")ownership $(format_ownership "$owner:$group") on $(format_path "$path")" | |
| success=false | |
| else | |
| log_success "Set $([ "$recursive" = "true" ] && echo "recursive ")ownership $(format_ownership "$owner:$group") on $(format_path "$path")" | |
| fi | |
| # Apply permissions if specified | |
| if [ -n "$permissions" ]; then | |
| local chmod_cmd="chmod" | |
| [ "$recursive" = "true" ] && chmod_cmd="chmod -R" | |
| if ! $chmod_cmd "$permissions" "$full_path" 2>/dev/null; then | |
| log_error "Failed to set $([ "$recursive" = "true" ] && echo "recursive ")permissions $(format_perms "$permissions") on $(format_path "$path")" | |
| success=false | |
| else | |
| log_success "Set $([ "$recursive" = "true" ] && echo "recursive ")permissions $(format_perms "$permissions") on $(format_path "$path")" | |
| fi | |
| fi | |
| # Check if any attributes couldn't be set due to read-only filesystem | |
| if ! touch "$full_path" 2>/dev/null; then | |
| log_warning "Read-only filesystem detected for $(format_path "$path")" | |
| fi | |
| return $([ "$success" = true ]) | |
| } | |
| log_warning "Starting new permission recovery session" | |
| # Statistics variables | |
| declare -i total=0 | |
| declare -i succeeded=0 | |
| declare -i failed=0 | |
| # Process each directory in order | |
| for entry in "${PERMISSION_LIST[@]}"; do | |
| ((total++)) | |
| if fix_permissions "$entry"; then | |
| ((succeeded++)) | |
| else | |
| ((failed++)) | |
| fi | |
| done | |
| log_warning "Completed: ${GREEN}${BOLD}$succeeded${NC}/${total} succeeded, ${RED}${BOLD}$failed${NC} failed" | |
| echo -e "\n${YELLOW}${BOLD}Logs are available at:${NC}" | |
| echo -e "Success log: ${GREEN}${BOLD}$SUCCESS_LOG${NC}" | |
| echo -e "Error log: ${RED}${BOLD}$ERROR_LOG${NC}" | |
| echo -e "Warning log: ${YELLOW}${BOLD}$WARN_LOG${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment