mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-11-11 13:07:35 +01:00
refactor: reduce code duplication from 1.97% to 0.76%
- Add common.sh library functions: require_imagemagick, install_missing_pacman_packages, handle_arg_help_or_unknown - Create android.sh shared library for Android utilities - Create hosts-guard-common.sh for pacman hooks shared functions - Update multiple scripts to source common.sh and use shared helpers - Add print_shutdown_schedule helper in setup_midnight_shutdown.sh - Remove duplicate log(), usage(), install_packages patterns across scripts - Format all shell scripts with shfmt (2-space indent)
This commit is contained in:
parent
355a19425d
commit
29c6be3189
91
hosts/guard/pacman-hooks/hosts-guard-common.sh
Normal file
91
hosts/guard/pacman-hooks/hosts-guard-common.sh
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared functions for hosts-guard pacman hooks
|
||||
# This file is sourced by pacman-pre-unlock-hosts.sh and pacman-post-relock-hosts.sh
|
||||
|
||||
TARGET=/etc/hosts
|
||||
LOGTAG=hosts-guard-hook
|
||||
|
||||
# Check if target has a read-only mount
|
||||
is_ro_mount() {
|
||||
findmnt -no OPTIONS -T "$TARGET" 2>/dev/null | grep -qw ro
|
||||
}
|
||||
|
||||
# Count mount layers for the target
|
||||
mount_layers_count() {
|
||||
awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0
|
||||
}
|
||||
|
||||
# Collapse all bind mount layers
|
||||
collapse_mounts() {
|
||||
local i=0
|
||||
if command -v mountpoint >/dev/null 2>&1; then
|
||||
while mountpoint -q "$TARGET"; do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
else
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop systemd units related to hosts guard
|
||||
stop_units_if_present() {
|
||||
local units=(hosts-bind-mount.service hosts-guard.path)
|
||||
for u in "${units[@]}"; do
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Remove immutable/append-only attributes
|
||||
remove_host_attrs() {
|
||||
if command -v lsattr >/dev/null 2>&1; then
|
||||
local attrs
|
||||
attrs=$(lsattr -d "$TARGET" 2>/dev/null || true)
|
||||
if echo "$attrs" | grep -q " i "; then
|
||||
chattr -i "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if echo "$attrs" | grep -q " a "; then
|
||||
chattr -a "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply immutable attribute
|
||||
apply_immutable() {
|
||||
if command -v chattr >/dev/null 2>&1; then
|
||||
chattr +i "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply a single read-only bind mount layer
|
||||
apply_ro_bind_mount() {
|
||||
mount --bind "$TARGET" "$TARGET" >/dev/null 2>&1 || true
|
||||
mount -o remount,ro,bind "$TARGET" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
# Start the path watcher service
|
||||
start_path_watcher() {
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl start hosts-guard.path >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Log to system logger and run log file
|
||||
log_hook() {
|
||||
local phase="$1"
|
||||
local state="$2"
|
||||
logger -t "$LOGTAG" "$phase: $state"
|
||||
echo "$(date -Is) $phase-$state" >>/run/hosts-guard-hook.log 2>/dev/null || true
|
||||
}
|
||||
@ -3,54 +3,30 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TARGET=/etc/hosts
|
||||
# Source shared functions
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=hosts-guard-common.sh
|
||||
source "$SCRIPT_DIR/hosts-guard-common.sh"
|
||||
|
||||
ENFORCE=/usr/local/sbin/enforce-hosts.sh
|
||||
LOGTAG=hosts-guard-hook
|
||||
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0; }
|
||||
collapse_mounts() {
|
||||
local i=0
|
||||
if command -v mountpoint >/dev/null 2>&1; then
|
||||
while mountpoint -q "$TARGET"; do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
else
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
done
|
||||
fi
|
||||
}
|
||||
log_hook "post" "relocking(start)"
|
||||
|
||||
# Ensure we end with a single read-only bind mount layer
|
||||
logger -t "$LOGTAG" "post: relocking /etc/hosts (starting)"
|
||||
echo "$(date -Is) post-relock(start)" >>/run/hosts-guard-hook.log 2>/dev/null || true
|
||||
# Collapse any stacked mounts first
|
||||
collapse_mounts
|
||||
|
||||
# Run enforcement script if available
|
||||
if [[ -x $ENFORCE ]]; then
|
||||
"$ENFORCE" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
if command -v chattr >/dev/null 2>&1; then
|
||||
chattr +i "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
# Apply protections
|
||||
apply_immutable
|
||||
apply_ro_bind_mount
|
||||
|
||||
# Apply exactly one ro bind layer
|
||||
mount --bind "$TARGET" "$TARGET" >/dev/null 2>&1 || true
|
||||
mount -o remount,ro,bind "$TARGET" >/dev/null 2>&1 || true
|
||||
# Start the path watcher
|
||||
start_path_watcher
|
||||
|
||||
# Start only the path watcher; avoid bind-mount service (we already bound once)
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl start hosts-guard.path >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
logger -t "$LOGTAG" "post: relocking /etc/hosts (done)"
|
||||
echo "$(date -Is) post-relock(done)" >>/run/hosts-guard-hook.log 2>/dev/null || true
|
||||
log_hook "post" "relocking(done)"
|
||||
|
||||
exit 0
|
||||
|
||||
@ -3,69 +3,27 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TARGET=/etc/hosts
|
||||
LOGTAG=hosts-guard-hook
|
||||
# Source shared functions
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=hosts-guard-common.sh
|
||||
source "$SCRIPT_DIR/hosts-guard-common.sh"
|
||||
|
||||
stop_units_if_present() {
|
||||
local units=(hosts-bind-mount.service hosts-guard.path)
|
||||
for u in "${units[@]}"; do
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
is_ro_mount() { findmnt -no OPTIONS -T "$TARGET" 2>/dev/null | grep -qw ro; }
|
||||
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0; }
|
||||
cleanup_mount_stacks() {
|
||||
local i=0
|
||||
# Unmount bind layers until /etc/hosts is no longer a mountpoint
|
||||
if command -v mountpoint >/dev/null 2>&1; then
|
||||
while mountpoint -q "$TARGET"; do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
else
|
||||
# Fallback to best-effort using mountinfo count
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Drop protective attributes if present
|
||||
if command -v lsattr >/dev/null 2>&1; then
|
||||
attrs=$(lsattr -d "$TARGET" 2>/dev/null || true)
|
||||
if echo "$attrs" | grep -q " i "; then
|
||||
chattr -i "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if echo "$attrs" | grep -q " a "; then
|
||||
chattr -a "$TARGET" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
# Remove protective attributes
|
||||
remove_host_attrs
|
||||
|
||||
# Stop guard services
|
||||
stop_units_if_present
|
||||
|
||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (starting)"
|
||||
echo "$(date -Is) pre-unlock" >>/run/hosts-guard-hook.log 2>/dev/null || true
|
||||
log_hook "pre" "unlocking(start)"
|
||||
|
||||
# Always collapse any existing layers; we'll operate on the plain file
|
||||
cleanup_mount_stacks
|
||||
# Collapse any existing mount layers
|
||||
collapse_mounts
|
||||
|
||||
# If someone managed a ro single-layer mount, ensure rw by remounting or collapsing again
|
||||
# Ensure writable by remounting if still read-only
|
||||
if is_ro_mount; then
|
||||
mount -o remount,rw "$TARGET" >/dev/null 2>&1 || cleanup_mount_stacks
|
||||
mount -o remount,rw "$TARGET" >/dev/null 2>&1 || collapse_mounts
|
||||
fi
|
||||
|
||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (done)"
|
||||
log_hook "pre" "unlocking(done)"
|
||||
|
||||
exit 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user