#!/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: IPdomain1 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 echo "# --- localhost generate ---#" printf "127.0.0.1" refresh_arrays for a in "${alias_names[@]}"; do printf " %s" "$a" done printf "\n\n" echo "# --- main not dynamic part --- #" [ -f "$MAINFOLD/main.conf" ] && sed -n '1,200p' "$MAINFOLD/main.conf" && printf "\n" refresh_arrays echo "# --- dynamic hosts --- #" for en in "${en_files[@]}"; do [ -f "$ENFOLD/$en.conf" ] && sed -n '1,500p' "$ENFOLD/$en.conf" && printf "\n" done echo "# --- end part ---#" [ -f "$MAINFOLD/endfile.conf" ] && sed -n '1,200p' "$MAINFOLD/endfile.conf" && printf "\n" else tmp="$out" : > "$tmp" echo "# --- localhost generate ---#" >> $tmp printf "127.0.0.1" >> "$tmp" refresh_arrays for a in "${alias_names[@]}"; do printf " %s" "$a" >> "$tmp" done printf "\n\n" >> "$tmp" echo "# --- main not dynamic part --- #" >> $tmp [ -f "$MAINFOLD/main.conf" ] && sed -n '1,200p' "$MAINFOLD/main.conf" >> "$tmp" && printf "\n" >> "$tmp" refresh_arrays echo "# --- dynamic hosts --- #" >> $tmp for en in "${en_files[@]}"; do [ -f "$ENFOLD/$en.conf" ] && sed -n '1,500p' "$ENFOLD/$en.conf" >> "$tmp" && printf "\n" >> "$tmp" done echo "# --- end part ---#" >> $tmp [ -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() { echo "###### HOST SIMULATION ######" _build_hosts_file "-" echo "###### HOST OVER ######" } #### RUN #### refresh_arrays usage() { cat < -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