381 lines
9.8 KiB
Bash
Executable File
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
|
|
|