FSA/spravuj_sdileni.sh

584 lines
20 KiB
Bash
Raw Normal View History

#!/bin/bash
# =============================================================================
# Universal Samba Share Manager - FSA (Fucking Samba Ass)
# =============================================================================
# Works on: Debian, Ubuntu, Arch Linux, RHEL/CentOS, Fedora
# Auto-detects distribution and installs Samba if needed
# =============================================================================
# Zkontrolujte, zda je skript spuštěn jako root
if [ "$EUID" -ne 0 ]; then
echo "Tento skript je nutné spustit s právy roota (sudo)."
exit 1
fi
# --- Detekce distribuce a správce balíčků ---
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO_ID="$ID"
DISTRO_NAME="$NAME"
elif [ -f /etc/arch-release ]; then
DISTRO_ID="arch"
DISTRO_NAME="Arch Linux"
elif [ -f /etc/debian_version ]; then
DISTRO_ID="debian"
DISTRO_NAME="Debian"
else
DISTRO_ID="unknown"
DISTRO_NAME="Unknown Linux"
fi
echo "Detected distribution: $DISTRO_NAME"
}
# --- Instalace Samby pokud není nainstalovaná ---
install_samba() {
echo "Kontroluji instalaci Samby..."
# Zkontroluj jestli už není Samba nainstalovaná
if command -v smbd &> /dev/null; then
echo "✅ Samba je již nainstalována."
return 0
fi
echo "⚠️ Samba není nainstalována. Instaluji..."
case "$DISTRO_ID" in
arch|manjaro)
pacman -Sy --noconfirm samba
;;
ubuntu|debian|linuxmint|pop)
apt-get update
apt-get install -y samba samba-common-bin
;;
fedora)
dnf install -y samba samba-common
;;
rhel|centos|rocky|almalinux)
yum install -y samba samba-common
;;
opensuse*|sles)
zypper install -y samba
;;
*)
echo "❌ CHYBA: Nepodařilo se detekovat distribuci pro automatickou instalaci."
echo "Prosím nainstalujte Sambu manuálně a spusťte skript znovu."
exit 1
;;
esac
if [ $? -eq 0 ]; then
echo "✅ Samba byla úspěšně nainstalována."
else
echo "❌ Instalace Samby selhala!"
exit 1
fi
}
# --- Auto-detekce uživatele a síťových rozhraní ---
DETECTED_USER="${SUDO_USER:-$(whoami)}"
DETECTED_INTERFACES=$(ip -o link show | awk -F': ' '{print $2}' | grep -v '^lo$' | tr '\n' ' ')
# --- Nastavení sdílení ---
declare -A SHARES=(
["${DETECTED_USER}-home"]="/home/${DETECTED_USER}|Domovska slozka uzivatele ${DETECTED_USER}|home"
["server-root"]="/|Celý server (root filesystem)|root"
)
CONFIG_FILE="/etc/samba/smb.conf"
BACKUP_FILE="/etc/samba/smb.conf.bak.$(date +%F_%T)"
# Spusť detekci distribuce a instalaci Samby
detect_distro
install_samba
# Funkce pro kontrolu existence smb.conf
check_config_exists() {
if [ ! -f "$CONFIG_FILE" ]; then
echo "Chyba: Konfigurační soubor $CONFIG_FILE neexistuje!"
echo "Pokud je Samba nově nainstalovaná, vytvořte ho z šablony příkazem:"
echo "sudo cp /etc/samba/smb.conf.default /etc/samba/smb.conf"
exit 1
fi
}
# VYLEPŠENÁ FUNKCE: Najde všechny diskové oddíly a správně očistí jejich názvy
discover_mounts() {
echo "Hledám všechny existující diskové oddíly..."
for key in "${!SHARES[@]}"; do
if [[ $key == disk-* ]]; then
unset SHARES[$key]
fi
done
while read -r name label uuid mountpoint; do
# Odstranění stromových znaků (└─, ├─) z názvu zařízení
name=$(echo "$name" | sed 's/^[├└]─//g' | sed 's/ //g')
local identifier="${label:-$name}"
local clean_identifier
clean_identifier=$(echo "$identifier" | sed 's/[^a-zA-Z0-9_-]//g')
# Záložní varianta pro prázdné popisky (např. se speciálními znaky)
if [ -z "$clean_identifier" ]; then
clean_identifier="$name"
fi
local share_name="disk-$clean_identifier"
local share_path=""
local status_info=""
if [ -n "$mountpoint" ]; then
share_path="$mountpoint"
local disk_info=$(df -h "$mountpoint" 2>/dev/null | tail -1 | awk '{print "("$2" celkem, "$4" volné)"}')
status_info="✅ Připojeno na $mountpoint $disk_info"
else
share_path="/mnt/$clean_identifier"
status_info="❌ Nepřipojeno (navrhovaná cesta: $share_path)"
fi
if [ -n "$clean_identifier" ]; then
SHARES["$share_name"]="$share_path|Oddíl $identifier|disk"
fi
done < <(lsblk -no NAME,LABEL,UUID,MOUNTPOINT -e7,1)
}
# Funkce pro vytvoření dfree skriptu pro konkrétní disk
create_dfree_script() {
local mount_point="$1"
local script_name="samba-dfree-$(basename "$mount_point").sh"
local script_path="/usr/local/bin/$script_name"
cat > "$script_path" << EOT
#!/bin/bash
# Auto-generated dfree script for $mount_point
MOUNT_PATH="$mount_point"
if [ -d "\$MOUNT_PATH" ]; then
df -k --output=size,avail "\$MOUNT_PATH" | tail -n 1
else
echo "0 0"
fi
EOT
chmod +x "$script_path"
echo "$script_path"
}
# Funkce pro vytvoření kompletní smb.conf s [global] sekcí
create_complete_smb_config() {
echo "Vytvářím kompletní SMB konfiguraci..."
local HOSTNAME=$(hostname | tr '[:lower:]' '[:upper:]')
cat > "$CONFIG_FILE" <<EOT
[global]
workgroup = WORKGROUP
server string = $DISTRO_NAME Server (%v)
netbios name = ${HOSTNAME}-SAMBA
security = user
encrypt passwords = yes
map to guest = Bad User
guest account = nobody
wins support = yes
local master = yes
domain master = yes
preferred master = yes
dns proxy = yes
min protocol = SMB2
max protocol = SMB3
server min protocol = SMB2
bind interfaces only = no
interfaces = lo $DETECTED_INTERFACES
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
smb ports = 445 8445
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
use sendfile = yes
aio read size = 16384
aio write size = 16384
log file = /var/log/samba/log.%m
max log size = 1000
log level = 1
load printers = no
printcap name = /dev/null
disable spoolss = yes
EOT
echo "Základní konfigurace vytvořena."
}
# OPRAVENÁ FUNKCE: Vytvoří sdílení se správným formátováním a `force user`
create_share() {
local share_name="$1"
if [ -z "$share_name" ]; then echo "Chybí název sdílení."; return 1; fi
if [ -z "${SHARES[$share_name]}" ]; then echo "Neznámé sdílení: $share_name"; return 1; fi
check_config_exists
IFS='|' read -r share_path comment share_type <<< "${SHARES[$share_name]}"
if grep -Fq "[$share_name]" "$CONFIG_FILE"; then echo "Chyba: Sdílení s názvem [$share_name] již existuje."; return 1; fi
if [ ! -d "$share_path" ]; then
echo "Varování: Cesta '$share_path' neexistuje."
read -p "Chcete ji vytvořit? (Y/n): " -n 1 -r; echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
if ! mkdir -p "$share_path"; then echo "Chyba: Nepodařilo se vytvořit adresář."; return 1; fi
echo "Adresář vytvořen."
else
echo "Operace zrušena."; return 1
fi
fi
echo "Přidávám nové sdílení '[$share_name]' do $CONFIG_FILE..."
case "$share_type" in
"home") cat <<EOT >> "$CONFIG_FILE"
[$share_name]
path = $share_path
writable = yes
guest ok = yes
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
comment = $comment
EOT
;;
"root") cat <<EOT >> "$CONFIG_FILE"
[$share_name]
path = $share_path
writable = yes
guest ok = no
valid users = $DETECTED_USER
admin users = $DETECTED_USER
force user = root
force group = root
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
comment = $comment
EOT
;;
"disk")
local dfree_script=$(create_dfree_script "$share_path")
local PRIMARY_GROUP=$(id -gn "$DETECTED_USER")
cat <<EOT >> "$CONFIG_FILE"
[$share_name]
path = $share_path
force user = $DETECTED_USER
writable = yes
guest ok = no
valid users = $DETECTED_USER
force group = $PRIMARY_GROUP
create mask = 0664
directory mask = 0775
dfree command = $dfree_script
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
comment = $comment
EOT
echo "Vytvořen dfree skript: $dfree_script"
;;
*) cat <<EOT >> "$CONFIG_FILE"
[$share_name]
path = $share_path
writable = yes
guest ok = yes
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
comment = $comment
EOT
;;
esac
if [ $? -eq 0 ]; then echo "Nové sdílení '$share_name' bylo přidáno."; else echo "Chyba při přidávání sdílení."; return 1; fi
}
# Funkce pro smazání sdílení
delete_share() {
local share_name="$1"
if [ -z "$share_name" ]; then echo "Použití: sudo $0 delete <název-sdílení>"; exit 1; fi
check_config_exists
if ! grep -Fq "[$share_name]" "$CONFIG_FILE"; then echo "Chyba: Sdílení [$share_name] nebylo nalezeno."; exit 1; fi
echo "Vytvářím zálohu..."; cp "$CONFIG_FILE" "$BACKUP_FILE"; echo "Mažu sdílení '[$share_name]'..."
awk -v section="[$share_name]" 'BEGIN{p=1} /^\[/{p=($0!=section)} p' "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
local dfree_script="/usr/local/bin/samba-dfree-${share_name#disk-}.sh"
if [ -f "$dfree_script" ]; then echo "Mažu dfree skript: $dfree_script"; rm -f "$dfree_script"; fi
echo "Sdílení '$share_name' bylo smazáno."
}
# Funkce pro zobrazení existujících sdílení
list_shares() {
check_config_exists
echo "Existující sdílení v $CONFIG_FILE:"; echo "=================================="
grep -E "^\[.*\]" "$CONFIG_FILE" | grep -v "\[global\]"
}
# Funkce pro vytvoření všech staticky definovaných sdílení
create_all() {
echo "Vytvářím všechna staticky definovaná sdílení..."
create_share "${DETECTED_USER}-home"
create_share "server-root"
}
# Funkce pro automatické vytvoření sdílení pro všechny disky
auto_discover_and_create() {
echo "=== AUTOMATICKÉ VYTVÁŘENÍ SDÍLENÍ PRO PŘIPOJENÉ DISKY ==="
for share_name in "${!SHARES[@]}"; do
IFS='|' read -r path comment share_type <<< "${SHARES[$share_name]}"
if [ "$share_type" = "disk" ]; then
if mountpoint -q "$path" 2>/dev/null; then
echo "--- Vytvářím sdílení pro připojený disk: $share_name ---"
create_share "$share_name"
fi
fi
done
}
# Funkce pro přidání [global] sekce do existující konfigurace
add_global_section() {
echo "=== PŘIDÁVÁNÍ [GLOBAL] SEKCE ==="
if grep -q "^\[global\]" "$CONFIG_FILE"; then echo "Sekce [global] již existuje."; return; fi
echo "Vytvářím zálohu..."; cp "$CONFIG_FILE" "$BACKUP_FILE"; echo "Přidávám [global] na začátek..."
local HOSTNAME=$(hostname | tr '[:lower:]' '[:upper:]')
local GLOBAL_CONFIG=$(cat <<EOT
[global]
workgroup = WORKGROUP
server string = $DISTRO_NAME Server (%v)
netbios name = ${HOSTNAME}-SAMBA
security = user
encrypt passwords = yes
map to guest = Bad User
guest account = nobody
wins support = yes
local master = yes
domain master = yes
preferred master = yes
dns proxy = yes
min protocol = SMB2
max protocol = SMB3
server min protocol = SMB2
bind interfaces only = no
interfaces = lo $DETECTED_INTERFACES
hosts allow = 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 100.64.0.0/10
smb ports = 445 8445
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
use sendfile = yes
aio read size = 16384
aio write size = 16384
log file = /var/log/samba/log.%m
max log size = 1000
log level = 1
load printers = no
printcap name = /dev/null
disable spoolss = yes
EOT
)
echo "$GLOBAL_CONFIG" | cat - "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
echo "Sekce [global] byla přidána."
}
# Funkce pro inicializaci kompletní konfigurace
init_config() {
echo "=== INICIALIZACE NOVÉ SMB KONFIGURACE ==="
if [ -f "$CONFIG_FILE" ]; then echo "Zálohuji stávající konfiguraci..."; mv "$CONFIG_FILE" "${CONFIG_FILE}.backup-$(date +%F_%T)"; fi
create_complete_smb_config
create_share "${DETECTED_USER}-home"
read -p "Přidat automaticky všechny nalezené PŘIPOJENÉ disky? (Y/n): " -n 1 -r; echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
auto_discover_and_create
fi
echo "Inicializace dokončena!"
}
# Funkce pro testování a restart
test_and_restart() {
echo ""; echo "Kontroluji syntaxi...";
if ! testparm -s > /dev/null 2>&1; then
echo "CHYBA: Konfigurace Samby je neplatná! Změny nebyly aplikovány."; testparm -s; exit 1
fi
echo "Restartuji služby SMB a NMB..."
# Detekuj správné názvy služeb pro různé distribuce
local SMB_SERVICE=""
local NMB_SERVICE=""
if systemctl list-unit-files | grep -q "^smbd.service"; then
SMB_SERVICE="smbd.service"
NMB_SERVICE="nmbd.service"
elif systemctl list-unit-files | grep -q "^smb.service"; then
SMB_SERVICE="smb.service"
NMB_SERVICE="nmb.service"
elif systemctl list-unit-files | grep -q "^samba.service"; then
SMB_SERVICE="samba.service"
NMB_SERVICE=""
fi
if [ -z "$SMB_SERVICE" ]; then
echo "CHYBA: Nepodařilo se najít Samba službu!"
exit 1
fi
# Aktivuj a restartuj služby
systemctl enable "$SMB_SERVICE" 2>/dev/null
if [ -n "$NMB_SERVICE" ]; then
systemctl enable "$NMB_SERVICE" 2>/dev/null
if systemctl restart "$SMB_SERVICE" "$NMB_SERVICE"; then
echo "Služby SMB úspěšně restartovány."
else
echo "CHYBA: Restart služeb selhal. Zkontrolujte logy pomocí 'journalctl -u $SMB_SERVICE'."
exit 1
fi
else
if systemctl restart "$SMB_SERVICE"; then
echo "Služby SMB úspěšně restartovány."
else
echo "CHYBA: Restart služeb selhal. Zkontrolujte logy pomocí 'journalctl -u $SMB_SERVICE'."
exit 1
fi
fi
echo "Hotovo! ✅"
}
# NOVÁ FUNKCE: Přidá záznam do /etc/fstab
add_to_fstab() {
local device_name="$1"; local mount_path="$2"
local device_info; device_info=$(lsblk -no UUID,FSTYPE "/dev/$device_name"); local uuid; uuid=$(echo "$device_info" | awk '{print $1}'); local fstype; fstype=$(echo "$device_info" | awk '{print $2}')
if [ -z "$uuid" ] || [ -z "$fstype" ]; then echo "Chyba: Nepodařilo se zjistit UUID."; return 1; fi
echo " - UUID: $uuid"; echo " - Typ: $fstype"
if grep -q "$uuid" /etc/fstab; then echo "Varování: Záznam pro UUID již existuje."; return 0; fi
local fstab_line="UUID=$uuid $mount_path $fstype defaults,nofail 0 2"
echo "Přidávám do /etc/fstab:"; echo " $fstab_line"
echo "" >> /etc/fstab; echo "# Přidáno skriptem spravuj_sdileni.sh dne $(date)" >> /etc/fstab; echo "$fstab_line" >> /etc/fstab
if [ $? -eq 0 ]; then echo "✅ Záznam úspěšně přidán."; else echo "Chyba: Zápis do /etc/fstab selhal."; return 1; fi
}
# NOVÁ FUNKCE: Interaktivně připojí a nasdílí disk
interactive_mount_and_create() {
local mode="$1"
echo "=== INTERAKTIVNÍ PŘIPOJENÍ A SDÍLENÍ DISKU ==="
local unmounted_partitions=()
while read -r name label uuid mountpoint; do
if [ -z "$mountpoint" ]; then
name=$(echo "$name" | sed 's/^[├└]─//g' | sed 's/ //g')
local identifier="${label:-$name}"
unmounted_partitions+=("$name|$identifier")
fi
done < <(lsblk -no NAME,LABEL,UUID,MOUNTPOINT -e7,1)
if [ ${#unmounted_partitions[@]} -eq 0 ]; then echo "Nenalezeny žádné nepřipojené diskové oddíly."; exit 0; fi
echo "Který oddíl chcete připojit a sdílet?"
local i=1
for info in "${unmounted_partitions[@]}"; do
IFS='|' read -r name identifier <<< "$info"; echo " $i) $name (Popisek: $identifier)"; i=$((i+1));
done
echo " 0) Zrušit"
local choice
read -p "Zadejte číslo: " choice
if ! [[ "$choice" =~ ^[0-9]+$ ]] || [ "$choice" -lt 0 ] || [ "$choice" -gt ${#unmounted_partitions[@]} ]; then echo "Chyba: Neplatná volba."; exit 1; fi
if [ "$choice" -eq 0 ]; then echo "Operace zrušena."; exit 0; fi
IFS='|' read -r selected_device selected_identifier <<< "${unmounted_partitions[$((choice-1))]}"
local clean_identifier; clean_identifier=$(echo "$selected_identifier" | sed 's/[^a-zA-Z0-9_-]//g')
if [ -z "$clean_identifier" ]; then
clean_identifier="$selected_device"
fi
local default_mount_path="/mnt/$clean_identifier"
read -p "Zadejte cestu pro připojení [navrženo: $default_mount_path]: " mount_path
mount_path="${mount_path:-$default_mount_path}"
if [ ! -d "$mount_path" ]; then echo "Vytvářím adresář $mount_path..."; if ! mkdir -p "$mount_path"; then echo "Chyba: Nelze vytvořit adresář."; exit 1; fi; fi
echo "Připojuji /dev/$selected_device na $mount_path..."
if ! mount "/dev/$selected_device" "$mount_path"; then echo "CHYBA: Nepodařilo se připojit disk! (mount /dev/$selected_device)"; exit 1; fi
echo "✅ Disk úspěšně připojen."
if [ "$mode" == "always" ]; then
echo ""; add_to_fstab "$selected_device" "$mount_path"
else
echo "INFO: Disk je připojen pouze dočasně."
fi
local share_name="disk-$clean_identifier"
echo ""; echo "Nyní vytvářím Samba sdílení s názvem '$share_name'..."
SHARES["$share_name"]="$mount_path|Oddíl $selected_identifier|disk"
create_share "$share_name"
}
# --- Hlavní logika skriptu (Router) ---
COMMAND="$1"
ARGUMENT1="$2"
ARGUMENT2="$3"
# Před spuštěním hlavního příkazu vždy aktualizujeme seznam disků
discover_mounts
# Zpracování parametru --mode=always, který může být na druhé nebo třetí pozici
MODE=""
if [ "$ARGUMENT1" == "--mode=always" ] || [ "$ARGUMENT2" == "--mode=always" ]; then
MODE="always"
fi
# Hlavní argument je ten, který není --mode=always
MAIN_ARG="$ARGUMENT1"
if [ "$ARGUMENT1" == "--mode=always" ]; then
MAIN_ARG="$ARGUMENT2"
fi
case "$COMMAND" in
mount-share)
interactive_mount_and_create "$MODE"
test_and_restart
;;
create)
create_share "$MAIN_ARG"
test_and_restart
;;
delete)
delete_share "$MAIN_ARG"
test_and_restart
;;
list)
list_shares
;;
create-all)
create_all
test_and_restart
;;
auto-disks)
auto_discover_and_create
test_and_restart
;;
discover)
echo ""
echo "Dostupná sdílení pro 'create':"
for name in "${!SHARES[@]}"; do
IFS='|' read -r path comment type <<< "${SHARES[$name]}"
echo " - $name (cesta: $path)"
done
;;
init)
init_config
test_and_restart
;;
add-global)
add_global_section
test_and_restart
;;
*)
echo "SMB Share Manager pro Arch Linux"
echo "================================="
echo "Použití: sudo $0 {příkaz} [argument]"
echo ""
echo "Hlavní příkazy:"
echo " mount-share [--mode=always] - Interaktivně připojí a nasdílí nepřipojený disk."
echo " init - Smaže starou a vytvoří novou, čistou konfiguraci."
echo " add-global - Přidá [global] sekci do existující konfigurace."
echo ""
echo "Správa sdílení:"
echo " discover - Najde a zobrazí všechny dostupné disky."
echo " auto-disks - Vytvoří sdílení pro všechny AKTUÁLNĚ PŘIPOJENÉ disky."
echo " create <název> - Vytvoří sdílení."
echo " create-all - Vytvoří statická sdílení (home, root)."
echo " delete <název> - Smaže existující sdílení."
echo " list - Vypíše nakonfigurovaná sdílení."
exit 1
;;
esac