Files
hosts-manager-generator/generator-hosts.sh
2025-11-07 12:33:57 +00:00

381 lines
9.8 KiB
Bash
Executable File

#!/bin/bash
# generator-hosts.sh
# Gestione hosts locali & disponibili/abilitati
# Usa come root (scrive /etc/hosts)
set -u
ROOTFOLD="/opt/hosts_config"
BKPFOLD="$ROOTFOLD/backups"
AVFOLD="$ROOTFOLD/hosts-available"
ENFOLD="$ROOTFOLD/hosts-enabled"
GEN_SCRIPT="$ROOTFOLD/generator-hosts.sh"
MAINFOLD="$ROOTFOLD/hosts-main"
ALIASFOLD="$ROOTFOLD/localhost-aliases"
FIRSTBACKUP="$BKPFOLD/firstbackup.bkp"
HOSTS="/etc/hosts"
mkdir -p "$BKPFOLD"
shopt -s nullglob
# Arrays (popolate dalla funzione refresh_arrays)
localhosts=()
en_files=()
av_files=()
ne_files=()
alias_files=()
alias_names=()
en_files_content=()
ne_files_content=()
refresh_arrays() {
localhosts=()
en_files=()
av_files=()
ne_files=()
alias_files=()
alias_names=()
en_files_content=()
ne_files_content=()
# local aliases
for f in "$ALIASFOLD"/*.lhost; do
[ -f "$f" ] || continue
alias_files+=("$(basename "$f" .lhost)")
alias_names+=("$(sed -n '1p' "$f")")
done
# enabled hosts
for f in "$ENFOLD"/*.conf; do
[ -f "$f" ] || continue
en_files+=("$(basename "$f" .conf)")
en_files_content+=("$(sed -n '1,200p' "$f")")
done
# available hosts
for f in "$AVFOLD"/*.conf; do
[ -f "$f" ] || continue
av_files+=("$(basename "$f" .conf)")
done
# disabled = available che non sono in enabled
for f in "$AVFOLD"/*.conf; do
[ -f "$f" ] || continue
name="$(basename "$f" .conf)"
if [ ! -f "$ENFOLD/$name.conf" ]; then
ne_files+=("$name")
ne_files_content+=("$(sed -n '1,200p' "$f")")
fi
done
}
_summary_line() {
echo "$1" | sed -n '1p'
}
#### ACTIONS ####
list_hosts_all() {
refresh_arrays
echo "[ List of all hosts ]"
echo ""
echo "---- Enabled Hosts ----"
if [ ${#en_files[@]} -eq 0 ]; then
echo " (none)"
else
for i in "${!en_files[@]}"; do
name="${en_files[$i]}"
content="${en_files_content[$i]:-}"
summary="$(_summary_line "$content")"
printf " %d) %s: %s\n" "$i" "$name" "$summary"
done
fi
echo ""
echo "---- Disabled Hosts ----"
if [ ${#ne_files[@]} -eq 0 ]; then
echo " (none)"
else
for i in "${!ne_files[@]}"; do
name="${ne_files[$i]}"
content="${ne_files_content[$i]:-}"
summary="$(_summary_line "$content")"
printf " %d) %s: %s\n" "$i" "$name" "$summary"
done
fi
}
enable_host() {
refresh_arrays
if [ ${#ne_files[@]} -eq 0 ]; then
echo "[ No disabled hosts available to enable ]"
return
fi
echo "[ Disabled hosts available to enable ]"
for i in "${!ne_files[@]}"; do
printf " %d) %s\n" "$i" "${ne_files[$i]}"
done
read -p "Insert the index to enable: " idx
if ! [[ "$idx" =~ ^[0-9]+$ ]] || [ "$idx" -ge "${#ne_files[@]}" ]; then
echo "[ Invalid index ]"
return
fi
sel="${ne_files[$idx]}"
src="$AVFOLD/$sel.conf"
dst="$ENFOLD/$sel.conf"
if [ -e "$dst" ]; then
echo "[ Already enabled: $sel ]"
return
fi
ln -s "$src" "$dst"
echo "[ Enabled host: $sel ]"
refresh_arrays
}
disable_host() {
refresh_arrays
if [ ${#en_files[@]} -eq 0 ]; then
echo "[ No enabled hosts to disable ]"
return
fi
echo "[ Enabled hosts ]"
for i in "${!en_files[@]}"; do
printf " %d) %s\n" "$i" "${en_files[$i]}"
done
read -p "Insert the index to disable: " idx
if ! [[ "$idx" =~ ^[0-9]+$ ]] || [ "$idx" -ge "${#en_files[@]}" ]; then
echo "[ Invalid index ]"
return
fi
sel="${en_files[$idx]}"
target="$ENFOLD/$sel.conf"
if [ ! -e "$target" ]; then
echo "[ Expected link not found: $target ]"
return
fi
unlink "$target"
echo "[ Disabled host: $sel ]"
refresh_arrays
}
list_local_alias() {
refresh_arrays
echo "[ Local aliases (index -> name) ]"
for i in "${!alias_files[@]}"; do
printf " %d) %s (file: %s.lhost)\n" "$i" "${alias_names[$i]}" "${alias_files[$i]}"
done
}
add_local_alias() {
refresh_arrays
read -p "Enter new local alias (e.g. grav.site): " newalias
newalias="${newalias// /}"
if [ -z "$newalias" ]; then
echo "[ Alias cannot be empty ]"
return
fi
next=1
while [ -e "$ALIASFOLD/$next.lhost" ]; do
((next++))
done
echo "$newalias" > "$ALIASFOLD/$next.lhost"
echo "[ Added alias '$newalias' as $next.lhost ]"
refresh_arrays
}
remove_local_alias() {
refresh_arrays
list_local_alias
read -p "Enter index of alias to remove: " idx
if ! [[ "$idx" =~ ^[0-9]+$ ]]; then
echo "[ Invalid index ]"
return
fi
if [ "$idx" -eq 0 ]; then
echo "[ Cannot remove 0.lhost (localhost) ]"
return
fi
file="$ALIASFOLD/$idx.lhost"
if [ ! -f "$file" ]; then
echo "[ No such alias file: $file ]"
return
fi
rm -f "$file"
echo "[ Removed alias index $idx ]"
refresh_arrays
}
show_main_config() {
echo "---- main.conf ----"
[ -f "$MAINFOLD/main.conf" ] && sed -n '1,200p' "$MAINFOLD/main.conf" || echo "(main.conf not found)"
echo ""
echo "---- endfile.conf ----"
[ -f "$MAINFOLD/endfile.conf" ] && sed -n '1,200p' "$MAINFOLD/endfile.conf" || echo "(endfile.conf not found)"
}
# NEW: create a new host file in hosts-available (asks name, ip, number of domains)
create_host() {
refresh_arrays
read -p "Enter new host filename (no extension, e.g. mysite): " name
name="${name// /}" # remove spaces
if [ -z "$name" ]; then
echo "[ Name cannot be empty ]"
return
fi
if [[ ! "$name" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "[ Invalid name: use only letters, numbers, . _ - ]"
return
fi
if [ -f "$AVFOLD/$name.conf" ] || [ -L "$ENFOLD/$name.conf" ] || [ -f "$ENFOLD/$name.conf" ]; then
echo "[ A host with that name already exists (available or enabled) ]"
return
fi
read -p "Enter IP address for this host (e.g. 192.168.1.10): " ip
ip="${ip// /}"
if [ -z "$ip" ]; then
echo "[ IP cannot be empty ]"
return
fi
# ask how many domains
read -p "How many domains do you want to add? (0 for none): " domcount
if ! [[ "$domcount" =~ ^[0-9]+$ ]]; then
echo "[ Invalid number ]"
return
fi
domains=""
if [ "$domcount" -gt 0 ]; then
for ((i=1;i<=domcount;i++)); do
read -p "Domain #$i (e.g. example.com): " d
d="${d// /}"
if [ -z "$d" ]; then
echo "[ Empty domain skipped ]"
continue
fi
domains="${domains} $d"
done
domains="${domains## }" # trim leading space
fi
# write file (single line: IP<TAB>domain1 domain2 ...)
{
if [ -z "$domains" ]; then
printf "%s\t%s\n" "$ip" "$name"
else
printf "%s\t%s\n" "$ip" "$domains"
fi
} > "$AVFOLD/$name.conf"
echo "[ Created $AVFOLD/$name.conf ]"
# ask whether enable now
read -p "Enable this host now? [y/N]: " yn
case "$yn" in
[Yy]* )
ln -s "$AVFOLD/$name.conf" "$ENFOLD/$name.conf"
echo "[ Enabled: $name ]"
;;
*) echo "[ Not enabled ]" ;;
esac
refresh_arrays
}
# Helper to build host contents (stdout or file)
_build_hosts_file() {
out="$1"
if [ "$out" = "-" ]; then
printf "127.0.0.1"
refresh_arrays
for a in "${alias_names[@]}"; do
printf " %s" "$a"
done
printf "\n\n"
[ -f "$MAINFOLD/main.conf" ] && sed -n '1,200p' "$MAINFOLD/main.conf" && printf "\n"
refresh_arrays
for en in "${en_files[@]}"; do
[ -f "$ENFOLD/$en.conf" ] && sed -n '1,500p' "$ENFOLD/$en.conf" && printf "\n"
done
[ -f "$MAINFOLD/endfile.conf" ] && sed -n '1,200p' "$MAINFOLD/endfile.conf" && printf "\n"
else
tmp="$out"
: > "$tmp"
printf "127.0.0.1" >> "$tmp"
refresh_arrays
for a in "${alias_names[@]}"; do
printf " %s" "$a" >> "$tmp"
done
printf "\n\n" >> "$tmp"
[ -f "$MAINFOLD/main.conf" ] && sed -n '1,200p' "$MAINFOLD/main.conf" >> "$tmp" && printf "\n" >> "$tmp"
refresh_arrays
for en in "${en_files[@]}"; do
[ -f "$ENFOLD/$en.conf" ] && sed -n '1,500p' "$ENFOLD/$en.conf" >> "$tmp" && printf "\n" >> "$tmp"
done
[ -f "$MAINFOLD/endfile.conf" ] && sed -n '1,200p' "$MAINFOLD/endfile.conf" >> "$tmp" && printf "\n" >> "$tmp"
fi
}
write_hosts() {
refresh_arrays
tmpfile="$(mktemp)"
_build_hosts_file "$tmpfile"
ts="$(date +%F_%H%M%S)"
mkdir -p "$BKPFOLD"
cp -a "$HOSTS" "$BKPFOLD/hosts.bkp.$ts" 2>/dev/null || true
mv "$tmpfile" "$HOSTS"
chmod 644 "$HOSTS"
echo "[ /etc/hosts written and backup saved as $BKPFOLD/hosts.bkp.$ts ]"
}
regenerate_hosts() {
write_hosts
}
simulate_hosts() {
_build_hosts_file "-"
}
#### RUN ####
refresh_arrays
usage() {
cat <<EOF
Usage: $0 <option>
-l List all hosts (enabled / disabled)
-e Enable host (choose from disabled list)
-d Disable host (choose from enabled list)
-c Create new host file (in hosts-available)
-r Regenerate /etc/hosts (writes file, makes backup)
-s Simulate /etc/hosts (print preview)
-hl List local hosts (aliases)
-ha Add local host (alias)
-hr Remove local host (alias) (cannot remove 0.lhost)
-sw Show main config (main.conf + endfile.conf)
EOF
}
case "${1:-}" in
-l) list_hosts_all ;;
-e) enable_host ;;
-d) disable_host ;;
-hl) list_local_alias ;;
-ha) add_local_alias ;;
-hr) remove_local_alias ;;
-sw) show_main_config ;;
-c) create_host ;;
-r) regenerate_hosts ;;
-s) simulate_hosts ;;
*) usage ;;
esac