Finish the pass: log_inspect, service_manager, rsync_magic, disk_cleanup

log_inspect.sh discarded grep's stderr and ignored its exit status, so
an unprivileged search over root-owned logs was indistinguishable from a
search that genuinely found nothing. grep's three outcomes now mean
three different things: matched, matched nothing, or could not read
everything -- the last of which says so and exits non-zero. Confirmed
grep returns 2 rather than 1 in that case, which is why the naive
"status -eq 1" check would never have fired.

service_manager.sh validates the action before dispatch and requires
root for the five that change system state, leaving status and list open
to anyone. $action is quoted at both call sites.

rsync_magic.sh had --inplace on unconditionally. It writes straight into
destination files instead of to a temporary and renaming, so an
interrupted run leaves them partially overwritten -- the opposite of
what a backup tool should guarantee. Now opt-in, with a warning when
used. Its log lives under /var/log and every line pipes through tee, so
under pipefail an unprivileged run died on the first line with a bare
permission error; it now falls back to stdout rather than failing the
sync over its own logging. --delete also confirms before running, since
reversing the two arguments erases the backup.

disk_cleanup.sh moves from `set -o pipefail` to full strict mode, with
the two pipelines that legitimately return non-zero handled at their
call sites rather than by leaving the script lax. Its "largest files"
walk also gained -xdev, which it was missing while security_audit.sh
next door already had it -- without it the walk descends /proc, /sys and
every network mount.

All fifteen scripts now run under set -euo pipefail.
This commit is contained in:
2026-08-22 22:24:50 -07:00
parent f8a86736f9
commit 96774aba35
4 changed files with 124 additions and 29 deletions
+14 -4
View File
@@ -32,7 +32,11 @@
# disk_cleanup.sh --clean --age 14 --dry-run # Preview cleanup with 14-day threshold
#
set -o pipefail
# Full strict mode. The two pipelines below that legitimately return
# non-zero -- find hitting unreadable directories, and head closing a
# pipe early -- are handled at their call sites rather than by leaving
# the whole script lax.
set -euo pipefail
# ===== CONFIGURATION =====
AGE_THRESHOLD=7
@@ -158,8 +162,12 @@ show_disk_usage() {
df -h -x tmpfs -x devtmpfs || error_exit "Failed to get disk usage information"
echo -e "\n==== Top 10 Largest Files ===="
find / -type f -printf '%s %p\n' 2>/dev/null | sort -nr | head -n 10 | \
awk '{size=$1/1024/1024; printf("%.1f MB - ", size); $1=""; print $0}' || \
# -xdev: without it this walks /proc, /sys and every network mount,
# which is slow and reports files that are not really taking up disk.
# The `|| true` absorbs both find's non-zero on unreadable directories
# and the SIGPIPE head causes once it has its ten lines.
{ find / -xdev -type f -printf '%s %p\n' 2>/dev/null | sort -nr | head -n 10 | \
awk '{size=$1/1024/1024; printf("%.1f MB - ", size); $1=""; print $0}'; } || \
echo "Warning: Could not retrieve largest files"
}
@@ -218,7 +226,9 @@ clean_temporary_files() {
# Count files that would be deleted
local file_count
file_count=$(find "$dir" -type f -mtime +"$AGE_THRESHOLD" 2>/dev/null | wc -l)
# `|| true` on the pipeline: find exits non-zero for unreadable
# subdirectories, which under pipefail would abort the whole cleanup.
file_count=$(find "$dir" -type f -mtime +"$AGE_THRESHOLD" 2>/dev/null | wc -l || true)
if [ "$file_count" -gt 0 ]; then
if [ "$DRY_RUN" = true ]; then