commit 9c97169799678794c235300d7ae280f25d68726a Author: mxnticek Date: Fri Jan 9 20:32:47 2026 +0100 Initial commit: Universal Samba share manager Features: - Auto-detects Linux distribution (Arch, Debian, Ubuntu, Fedora, RHEL, etc.) - Auto-installs Samba if not present - Auto-detects current user and network interfaces - Supports disk discovery and management - Optional persistent mounting via /etc/fstab - Safe configuration management with backups Co-Authored-By: Claude Sonnet 4.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..25c6098 --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# FSA - Fucking Samba Ass + +Universal Samba share management script that works across all major Linux distributions. + +## Features + +- 🔍 **Auto-detection**: Automatically detects your Linux distribution +- 📦 **Auto-installation**: Installs Samba if not already present +- 👤 **User-aware**: Automatically detects the current user +- 🌐 **Network-aware**: Auto-detects network interfaces +- 💾 **Disk management**: Discovers and manages disk shares +- 🔄 **Persistent mounts**: Optionally adds disks to /etc/fstab for auto-mount on boot +- 🛡️ **Safe**: Creates backups before modifying configuration + +## Supported Distributions + +- Arch Linux / Manjaro +- Debian / Ubuntu / Linux Mint / Pop!_OS +- Fedora +- RHEL / CentOS / Rocky Linux / AlmaLinux +- openSUSE / SLES + +## Installation + +1. Download the script: +```bash +wget https://forgejo.mxnticek.eu/mxnticek/FSA/raw/branch/main/spravuj_sdileni.sh +chmod +x spravuj_sdileni.sh +``` + +2. Run with sudo (the script will auto-install Samba if needed): +```bash +sudo ./spravuj_sdileni.sh +``` + +## Usage + +### Initialize Configuration +Create a fresh Samba configuration with your user's home directory: +```bash +sudo ./spravuj_sdileni.sh init +``` + +### Mount and Share a Disk + +**Temporary mount** (until reboot): +```bash +sudo ./spravuj_sdileni.sh mount-share +``` + +**Permanent mount** (adds to /etc/fstab): +```bash +sudo ./spravuj_sdileni.sh mount-share --mode=always +``` + +### Manage Shares + +**Discover available disks**: +```bash +sudo ./spravuj_sdileni.sh discover +``` + +**List configured shares**: +```bash +sudo ./spravuj_sdileni.sh list +``` + +**Create a specific share**: +```bash +sudo ./spravuj_sdileni.sh create +``` + +**Delete a share**: +```bash +sudo ./spravuj_sdileni.sh delete +``` + +**Auto-create shares for all mounted disks**: +```bash +sudo ./spravuj_sdileni.sh auto-disks +``` + +## Share Types + +The script creates different types of shares: + +### Home Share +- Read/write access for all users +- Guest access enabled +- Shares your user's home directory + +### Root Share +- Full filesystem access +- Requires authentication +- Only accessible by the detected user +- Runs with root privileges + +### Disk Shares +- Automatically configured for external disks +- Custom dfree scripts for accurate disk space reporting +- Proper permissions (664/775) +- Force user/group settings + +## Configuration + +All shares include: +- SMB2/SMB3 protocol support +- Network restrictions (local networks only) +- Optimized socket options +- Performance tuning (sendfile, AIO) + +Default allowed networks: +- 127.0.0.1 (localhost) +- 192.168.0.0/16 (private network) +- 10.0.0.0/8 (private network) +- 172.16.0.0/12 (private network) +- 100.64.0.0/10 (CGNAT/Tailscale) + +## Advanced Usage + +### Add [global] section to existing config +```bash +sudo ./spravuj_sdileni.sh add-global +``` + +### Create all static shares (home + root) +```bash +sudo ./spravuj_sdileni.sh create-all +``` + +## Troubleshooting + +### Check service status +```bash +sudo systemctl status smbd nmbd +# or on some distros: +sudo systemctl status smb nmb +``` + +### View logs +```bash +sudo journalctl -u smbd -u nmbd -f +``` + +### Test configuration +```bash +sudo testparm +``` + +### Check which shares are visible +```bash +smbclient -L localhost -N +``` + +## Security Notes + +- Always review the generated configuration +- Shares are restricted to local networks by default +- Root share requires authentication +- Guest access is only enabled for home shares by default + +## License + +Do whatever the fuck you want with it. + +## Author + +Created with frustration and love for Samba configuration. diff --git a/spravuj_sdileni.sh b/spravuj_sdileni.sh new file mode 100755 index 0000000..0a66eae --- /dev/null +++ b/spravuj_sdileni.sh @@ -0,0 +1,583 @@ +#!/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" <> "$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 <> "$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 <> "$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 <> "$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 "; 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 < "${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 - Vytvoří sdílení." + echo " create-all - Vytvoří statická sdílení (home, root)." + echo " delete - Smaže existující sdílení." + echo " list - Vypíše nakonfigurovaná sdílení." + exit 1 + ;; +esac