#!/bin/sh # (c) 2023 Stefan Agner # This scripts attempts to clear corrupted Docker overlay2 storage metadata # which can be left over after a power failure. # See also: https://github.com/moby/moby/issues/42964 # # Typically the error message when attempting to pull the image for which # corrupted layers are in the storage looks like: # failed to register layer: error creating overlay mount to /mnt/data/docker/overlay2/6ee02298ee75a4f96e77f90551673cb700f29867f9ad1c4e20b8c816bfcf0735/merged: too many levels of symbolic links # Docker storage directory, intended for Home Assistant OS docker_storage_dir="/mnt/data/docker" # Warning message echo "WARNING: This script attempts to clear corrupted Docker overlay2 storage metadata." echo "Use with caution, as it may result in data loss. Ensure you have backups before running this script." # Initial sanity check for the overlay2 directory overlay2_dir="$docker_storage_dir/overlay2" layerdb_dir="$docker_storage_dir/image/overlay2/layerdb/sha256" if [ ! -d "$overlay2_dir" ]; then echo "Error: Directory $overlay2_dir does not exist." exit 1 fi # Find unique cache IDs cache_ids=$(find "$overlay2_dir" -type f -size 0 \( -name lower -o -name link \) -exec sh -c 'basename $(dirname {})' \; | sort -u) # Check if cache IDs are found if [ -z "$cache_ids" ]; then echo "No cache IDs with size 0 found. Exiting." exit 0 fi # Count the number of cache IDs found num_cache_ids=$(echo "$cache_ids" | wc -w) # Prompt the user for confirmation echo "Found $num_cache_ids cache IDs with size 0. Do you want to continue and delete them? (yes/no)" read user_confirmation # Check user's response if [ "$user_confirmation" != "yes" ]; then echo "Operation canceled. No directories were deleted." exit 0 fi # Initialize counters for summary deleted_cache_dirs=0 deleted_layerdb_dirs=0 # Iterate through cache IDs for cache_id in $cache_ids; do # Find corresponding directory in layerdb layerdb_dir_path=$(dirname $(grep -r -e "$cache_id" "$layerdb_dir"/*/cache-id)) cache_dir="$overlay2_dir/$cache_id" # Remove cache directory if [ -d "$cache_dir" ]; then rm -rf "$cache_dir" deleted_cache_dirs=$((deleted_cache_dirs + 1)) fi # Remove LayerDB directory if [ -d "$layerdb_dir_path" ]; then rm -rf "$layerdb_dir_path" deleted_layerdb_dirs=$((deleted_layerdb_dirs + 1)) fi done # Print summary echo "Summary: Deleted $deleted_cache_dirs cache directories and $deleted_layerdb_dirs LayerDB directories."