fix(safeclean): dry-run/apply docker consistency, eCryptfs warning, rotated log cleanup
This commit is contained in:
parent
f4486d3c3c
commit
37233f0a47
62
safeclean.sh
Normal file → Executable file
62
safeclean.sh
Normal file → Executable file
|
|
@ -279,14 +279,44 @@ clean_docker() {
|
|||
if ! docker info >/dev/null 2>&1; then
|
||||
printf ' %-26s %sdaemon not reachable%s\n' "Docker" "$c_dim" "$c_rst"; return
|
||||
fi
|
||||
|
||||
local age_h=$(( AGE_DAYS * 24 ))
|
||||
|
||||
echo " Docker reclaimable space:"
|
||||
docker system df 2>/dev/null | sed 's/^/ /'
|
||||
[ "$DRY_RUN" = 1 ] && return
|
||||
|
||||
if [ "$DRY_RUN" = 1 ]; then
|
||||
if [ "$AGGRESSIVE_DOCKER" = 0 ] && [ "$AGE_DAYS" -gt 0 ]; then
|
||||
# apply uses --filter until=Xh, so docker system df overstates actual reclaim.
|
||||
# Estimate: sum sizes of dangling images older than age_h hours (what prune targets).
|
||||
local img_bytes=0 img_count=0 id s
|
||||
while IFS= read -r id; do
|
||||
[ -z "$id" ] && continue
|
||||
img_count=$(( img_count + 1 ))
|
||||
s=$(docker image inspect --format '{{.Size}}' "$id" 2>/dev/null) || s=0
|
||||
img_bytes=$(( img_bytes + ${s:-0} ))
|
||||
done < <(docker image ls --filter "dangling=true" --filter "until=${age_h}h" \
|
||||
--format "{{.ID}}" 2>/dev/null)
|
||||
local img_human
|
||||
img_human=$(numfmt --to=si --suffix=B -- "$img_bytes" 2>/dev/null \
|
||||
|| echo "${img_bytes}B")
|
||||
echo
|
||||
printf ' %sNOTE: apply uses --filter until=%dh — only items older than %d day(s) are removed.%s\n' \
|
||||
"$c_yel" "$age_h" "$AGE_DAYS" "$c_rst"
|
||||
printf ' Dangling images >%dd apply would actually remove: %s%s%s (%d image(s))\n' \
|
||||
"$AGE_DAYS" "$c_bold" "$img_human" "$c_rst" "$img_count"
|
||||
printf ' %s(stopped containers + build cache also contribute; totals shown above)%s\n' \
|
||||
"$c_dim" "$c_rst"
|
||||
printf ' %sTip: --docker-all removes ALL unused images regardless of age.%s\n' \
|
||||
"$c_dim" "$c_rst"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
local flags="-f"
|
||||
[ "$AGGRESSIVE_DOCKER" = 1 ] && flags="-af" # -a also removes unused (not just dangling) images
|
||||
local until_args=()
|
||||
[ "$AGE_DAYS" -gt 0 ] && until_args=(--filter "until=$(( AGE_DAYS * 24 ))h")
|
||||
[ "$AGE_DAYS" -gt 0 ] && until_args=(--filter "until=${age_h}h")
|
||||
if confirm "Run 'docker system prune ${flags} ${until_args[*]}' (volumes are NOT touched)?"; then
|
||||
docker system prune $flags "${until_args[@]}"
|
||||
else
|
||||
|
|
@ -298,9 +328,16 @@ clean_system() {
|
|||
echo
|
||||
echo "${c_bold}System (sudo) ─────────────────────────────────────────────${c_rst}"
|
||||
if [ "$DRY_RUN" = 1 ]; then
|
||||
echo " ${c_dim}dry-run: would offer apt clean, journald vacuum, old snap removal${c_rst}"
|
||||
echo " ${c_dim}dry-run: would offer apt clean, journald vacuum, rotated log cleanup, old snap removal${c_rst}"
|
||||
echo " apt archive cache:"; sudo -n du -sh /var/cache/apt/archives 2>/dev/null | sed 's/^/ /' || true
|
||||
echo " journal logs:"; journalctl --disk-usage 2>/dev/null | sed 's/^/ /' || true
|
||||
echo " rotated logs (/var/log/*.gz, *.1, *.2 …):"
|
||||
local rot_total
|
||||
rot_total=$(find /var/log -maxdepth 1 -type f \
|
||||
\( -name '*.gz' -o -name '*.[0-9]' -o -name '*.[0-9][0-9]' \) \
|
||||
-print0 2>/dev/null | xargs -0 -r du -sch 2>/dev/null \
|
||||
| tail -n1 | awk '{print $1}') || rot_total=""
|
||||
printf ' %s%s%s\n' "$c_bold" "${rot_total:-0}" "$c_rst"
|
||||
return
|
||||
fi
|
||||
|
||||
|
|
@ -314,6 +351,22 @@ clean_system() {
|
|||
sudo journalctl --vacuum-time="${jdays}d"
|
||||
fi
|
||||
|
||||
local rotated=()
|
||||
while IFS= read -r -d '' f; do rotated+=("$f"); done < <(
|
||||
find /var/log -maxdepth 1 -type f \
|
||||
\( -name '*.gz' -o -name '*.[0-9]' -o -name '*.[0-9][0-9]' \) \
|
||||
-print0 2>/dev/null
|
||||
)
|
||||
if [ ${#rotated[@]} -gt 0 ]; then
|
||||
local rot_size
|
||||
rot_size=$(du -sch "${rotated[@]}" 2>/dev/null | tail -n1 | awk '{print $1}')
|
||||
if confirm "Delete rotated system logs (${rot_size}, ${#rotated[@]} file(s) — not active logs)?"; then
|
||||
sudo rm -f -- "${rotated[@]}" && printf ' %sremoved.%s\n' "$c_grn" "$c_rst"
|
||||
else
|
||||
echo " skipped."
|
||||
fi
|
||||
fi
|
||||
|
||||
if confirm "snap: remove disabled (old) revisions?"; then
|
||||
snap list --all 2>/dev/null | awk '/disabled/{print $1, $3}' | \
|
||||
while read -r name rev; do
|
||||
|
|
@ -342,6 +395,9 @@ echo
|
|||
|
||||
echo "${c_bold}Largest items under $SCAN_ROOT:${c_rst}"
|
||||
du -h --max-depth=1 "$SCAN_ROOT" 2>/dev/null | sort -rh | head -n 12 | sed 's/^/ /'
|
||||
if [ -d "${SCAN_ROOT}/.Private" ] && mount 2>/dev/null | grep -q " on ${SCAN_ROOT} type ecryptfs"; then
|
||||
printf ' %sNote: eCryptfs detected — .Private and home directory are the same data; sizes above may be double-counted.%s\n' "$c_yel" "$c_rst"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "${c_bold}Reclaimable categories ──────────────────────────────────────${c_rst}"
|
||||
|
|
|
|||
Loading…
Reference in a new issue