111 lines
3.3 KiB
Bash
111 lines
3.3 KiB
Bash
#!/bin/bash
|
||
|
||
set -euo pipefail
|
||
shopt -s lastpipe
|
||
|
||
UID_MAP="/etc/jimlab/uid.map"
|
||
SUBID_MAP="/etc/jimlab/subid.map"
|
||
DEFAULT_SUBID_SIZE=4096
|
||
|
||
if [[ ! -f "$UID_MAP" ]]; then
|
||
echo "❌ Error: $UID_MAP not found."
|
||
exit 1
|
||
fi
|
||
|
||
touch "$SUBID_MAP"
|
||
|
||
# Return true if two ranges [start1, end1) and [start2, end2) overlap
|
||
ranges_overlap() {
|
||
local start1=$1
|
||
local size1=$2
|
||
local start2=$3
|
||
local size2=$4
|
||
|
||
[[ -z "$start1" || -z "$size1" || -z "$start2" || -z "$size2" ]] && return 1
|
||
[[ ! "$start1" =~ ^[0-9]+$ || ! "$size1" =~ ^[0-9]+$ || ! "$start2" =~ ^[0-9]+$ || ! "$size2" =~ ^[0-9]+$ ]] && return 1
|
||
|
||
local end1=$((start1 + size1))
|
||
local end2=$((start2 + size2))
|
||
|
||
[[ $start1 -lt $end2 && $start2 -lt $end1 ]]
|
||
}
|
||
|
||
# Get next available subid base
|
||
get_next_subid_base() {
|
||
local max=100000
|
||
grep -v '^\s*$' "$SUBID_MAP" | while IFS=: read -r _ base size; do
|
||
base=$(echo "$base" | xargs)
|
||
size=$(echo "$size" | xargs)
|
||
[[ "$base" =~ ^[0-9]+$ && "$size" =~ ^[0-9]+$ ]] || continue
|
||
local end=$((base + size))
|
||
(( end > max )) && max=$end
|
||
done
|
||
echo "$max"
|
||
}
|
||
|
||
# Warn if overlapping any prior block
|
||
check_overlap() {
|
||
local new_start=$1
|
||
local new_size=$2
|
||
grep -v '^\s*$' "$SUBID_MAP" | while IFS=: read -r user base size; do
|
||
if ranges_overlap "$new_start" "$new_size" "$base" "$size"; then
|
||
echo "⚠️ Warning: new block $new_start:$new_size overlaps with $user:$base:$size" >&2
|
||
fi
|
||
done
|
||
}
|
||
|
||
grep -v '^\s*$' "$UID_MAP" | while IFS=: read -r service uid; do
|
||
service=$(echo "$service" | xargs)
|
||
uid=$(echo "$uid" | xargs)
|
||
home="/var/lib/$service"
|
||
|
||
[[ -z "$service" || -z "$uid" || "$service" == \#* ]] && continue
|
||
|
||
echo "▶️ Processing $service (UID=$uid, HOME=$home)"
|
||
|
||
# Create group if missing
|
||
if ! getent group "$service" > /dev/null; then
|
||
echo " ➕ Creating group $service with GID $uid"
|
||
groupadd --system --gid "$uid" "$service"
|
||
fi
|
||
|
||
# Create or fix user
|
||
if ! id "$service" &>/dev/null; then
|
||
echo " ➕ Creating user $service with UID $uid and home $home"
|
||
useradd --system --uid "$uid" --gid "$uid" --home-dir "$home" --create-home --shell /sbin/nologin "$service"
|
||
else
|
||
current_home=$(getent passwd "$service" | cut -d: -f6)
|
||
if [[ "$current_home" != "$home" ]]; then
|
||
echo " 🛠 Updating home dir for $service → $home"
|
||
usermod -d "$home" "$service"
|
||
mkdir -p "$home"
|
||
chown "$service:$service" "$home"
|
||
fi
|
||
fi
|
||
|
||
# Enable lingering
|
||
if ! loginctl show-user "$uid" &>/dev/null || ! loginctl show-user "$uid" | grep -q "Linger=yes"; then
|
||
echo " 🔄 Enabling lingering for $service"
|
||
loginctl enable-linger "$service"
|
||
fi
|
||
|
||
# Subuid/subgid mapping
|
||
if ! grep -q "^$service:" "$SUBID_MAP"; then
|
||
next_base=$(get_next_subid_base)
|
||
check_overlap "$next_base" "$DEFAULT_SUBID_SIZE"
|
||
echo " 📦 Assigning subid range: $service:$next_base:$DEFAULT_SUBID_SIZE"
|
||
echo "$service:$next_base:$DEFAULT_SUBID_SIZE" >> "$SUBID_MAP"
|
||
fi
|
||
|
||
# Sync to /etc/subuid and /etc/subgid
|
||
map_line=$(grep "^$service:" "$SUBID_MAP" | head -n1)
|
||
for file in /etc/subuid /etc/subgid; do
|
||
if ! grep -q "^$service:" "$file"; then
|
||
echo "$map_line" | sudo tee -a "$file" >/dev/null
|
||
elif ! grep -q "^$map_line\$" "$file"; then
|
||
echo "⚠️ Mismatch in $file for $service. Check manually!" >&2
|
||
fi
|
||
done
|
||
|
||
done
|