Setup installation
This commit is contained in:
334
scripts/ssd-detection/ssd-safe-eject.sh
Normal file
334
scripts/ssd-detection/ssd-safe-eject.sh
Normal file
@@ -0,0 +1,334 @@
|
||||
#!/bin/bash
|
||||
# ssd-safe-eject.sh - Safe Eject Extension für USB-C SSDs
|
||||
# Zweck: Sichere Entfernung von USB-C SSDs mit vollständigem Sync und Hardware-Eject
|
||||
|
||||
set -e
|
||||
|
||||
# Konfiguration
|
||||
MOUNT_POINT="/mnt/ssd-storage"
|
||||
LOG_FILE="/var/log/ssd-mount.log"
|
||||
|
||||
# Farben für Ausgabe
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging-Funktion
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - SAFE-EJECT: $1" | sudo tee -a "$LOG_FILE"
|
||||
echo -e "${BLUE}[SAFE-EJECT]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - SUCCESS: $1" | sudo tee -a "$LOG_FILE"
|
||||
echo -e "${GREEN}[✓]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - WARNING: $1" | sudo tee -a "$LOG_FILE"
|
||||
echo -e "${YELLOW}[!]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - ERROR: $1" | sudo tee -a "$LOG_FILE"
|
||||
echo -e "${RED}[✗]${NC} $1"
|
||||
}
|
||||
|
||||
# Schritt 1: Pre-Eject Validierung
|
||||
validate_pre_eject() {
|
||||
log_message "Validiere Pre-Eject Status..."
|
||||
|
||||
if ! mountpoint -q "$MOUNT_POINT"; then
|
||||
log_warning "Keine SSD auf $MOUNT_POINT gemountet"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mounted_device=$(df "$MOUNT_POINT" | tail -1 | awk '{print $1}')
|
||||
log_success "Gemountetes Device identifiziert: $mounted_device"
|
||||
|
||||
# Prüfe ob Device USB-Device ist
|
||||
device_base=$(echo "$mounted_device" | sed 's/[0-9]*$//')
|
||||
if lsblk -o TRAN "$device_base" 2>/dev/null | grep -q usb; then
|
||||
log_success "USB-Device bestätigt: $device_base"
|
||||
echo "$mounted_device"
|
||||
return 0
|
||||
else
|
||||
log_error "Device ist kein USB-Device - Safe-Eject nicht anwendbar"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Schritt 2: Aktive Prozesse prüfen
|
||||
check_active_processes() {
|
||||
local device="$1"
|
||||
log_message "Prüfe aktive Prozesse auf $MOUNT_POINT..."
|
||||
|
||||
# Prozesse finden die das Mount-Point verwenden
|
||||
active_processes=$(lsof "$MOUNT_POINT" 2>/dev/null || true)
|
||||
|
||||
if [ -n "$active_processes" ]; then
|
||||
log_warning "Aktive Prozesse gefunden:"
|
||||
echo "$active_processes"
|
||||
echo ""
|
||||
echo "Prozesse beenden? (y/n/s für skip)"
|
||||
read -r response
|
||||
|
||||
case "$response" in
|
||||
"y"|"Y")
|
||||
log_message "Beende Prozesse..."
|
||||
lsof -t "$MOUNT_POINT" 2>/dev/null | xargs -r sudo kill -TERM
|
||||
sleep 2
|
||||
# Prüfe erneut
|
||||
remaining=$(lsof "$MOUNT_POINT" 2>/dev/null || true)
|
||||
if [ -n "$remaining" ]; then
|
||||
log_warning "Einige Prozesse laufen noch - Force Kill..."
|
||||
lsof -t "$MOUNT_POINT" 2>/dev/null | xargs -r sudo kill -KILL
|
||||
fi
|
||||
log_success "Prozesse beendet"
|
||||
;;
|
||||
"s"|"S")
|
||||
log_warning "Prozesse werden nicht beendet - Fortfahren auf eigene Gefahr"
|
||||
;;
|
||||
*)
|
||||
log_message "Safe-Eject abgebrochen"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
log_success "Keine aktiven Prozesse gefunden"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Schritt 3: Vollständiger Daten-Sync
|
||||
perform_full_sync() {
|
||||
log_message "Führe vollständigen Daten-Sync durch..."
|
||||
|
||||
# Globaler Sync
|
||||
log_message "Globaler Sync..."
|
||||
sync
|
||||
|
||||
# Warte auf Dirty Pages Flush
|
||||
log_message "Warte auf Buffer-Flush..."
|
||||
local timeout=30
|
||||
local count=0
|
||||
|
||||
while [ $count -lt $timeout ]; do
|
||||
dirty_pages=$(cat /proc/meminfo | grep "Dirty:" | awk '{print $2}')
|
||||
writeback_pages=$(cat /proc/meminfo | grep "Writeback:" | awk '{print $2}')
|
||||
|
||||
if [ "$dirty_pages" -le 4 ] && [ "$writeback_pages" -le 4 ]; then
|
||||
log_success "Buffer-Flush abgeschlossen (Dirty: ${dirty_pages}kB, Writeback: ${writeback_pages}kB)"
|
||||
break
|
||||
fi
|
||||
|
||||
if [ $((count % 5)) -eq 0 ]; then
|
||||
log_message "Warte auf Buffer-Flush... (Dirty: ${dirty_pages}kB, Writeback: ${writeback_pages}kB)"
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
if [ $count -ge $timeout ]; then
|
||||
log_warning "Buffer-Flush Timeout erreicht - Fortfahren..."
|
||||
fi
|
||||
|
||||
# Finaler Sync
|
||||
log_message "Finaler Sync..."
|
||||
sync
|
||||
sleep 2
|
||||
|
||||
log_success "Vollständiger Sync abgeschlossen"
|
||||
}
|
||||
|
||||
# Schritt 4: Filesystem Unmount
|
||||
perform_unmount() {
|
||||
local device="$1"
|
||||
log_message "Unmounte Dateisystem: $device"
|
||||
|
||||
# Lazy Unmount falls normal unmount fehlschlägt
|
||||
if ! sudo umount "$MOUNT_POINT" 2>/dev/null; then
|
||||
log_warning "Normaler Unmount fehlgeschlagen - versuche Lazy Unmount..."
|
||||
|
||||
if sudo umount -l "$MOUNT_POINT" 2>/dev/null; then
|
||||
log_success "Lazy Unmount erfolgreich"
|
||||
else
|
||||
log_error "Unmount fehlgeschlagen"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_success "Unmount erfolgreich"
|
||||
fi
|
||||
|
||||
# Verifikation
|
||||
if mountpoint -q "$MOUNT_POINT"; then
|
||||
log_error "Mount-Point noch aktiv nach Unmount"
|
||||
return 1
|
||||
else
|
||||
log_success "Mount-Point erfolgreich getrennt"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Schritt 5: Hardware-Eject
|
||||
perform_hardware_eject() {
|
||||
local device="$1"
|
||||
local device_base=$(echo "$device" | sed 's/[0-9]*$//')
|
||||
|
||||
log_message "Hardware-Eject für Device: $device_base"
|
||||
|
||||
# Prüfe ob eject verfügbar ist
|
||||
if ! command -v eject >/dev/null; then
|
||||
log_warning "eject Befehl nicht verfügbar - installiere eject..."
|
||||
sudo apt update && sudo apt install -y eject
|
||||
fi
|
||||
|
||||
# Hardware-Eject durchführen
|
||||
if sudo eject "$device_base" 2>/dev/null; then
|
||||
log_success "Hardware-Eject erfolgreich: $device_base"
|
||||
else
|
||||
log_warning "Hardware-Eject fehlgeschlagen - möglicherweise nicht unterstützt"
|
||||
|
||||
# Alternative: USB-Device über sysfs deaktivieren
|
||||
usb_device=$(udevadm info --query=path --name="$device_base" 2>/dev/null | sed 's|/block/.*||')
|
||||
if [ -n "$usb_device" ]; then
|
||||
log_message "Versuche USB-Device Deaktivierung über sysfs..."
|
||||
if echo 1 | sudo tee "/sys$usb_device/remove" >/dev/null 2>&1; then
|
||||
log_success "USB-Device über sysfs deaktiviert"
|
||||
else
|
||||
log_warning "USB-Device Deaktivierung fehlgeschlagen"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Schritt 6: Post-Eject Validierung
|
||||
validate_post_eject() {
|
||||
local device="$1"
|
||||
local device_base=$(echo "$device" | sed 's/[0-9]*$//')
|
||||
|
||||
log_message "Post-Eject Validierung..."
|
||||
|
||||
# Prüfe ob Mount-Point noch aktiv
|
||||
if mountpoint -q "$MOUNT_POINT"; then
|
||||
log_error "Mount-Point noch aktiv - Safe-Eject unvollständig"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Prüfe ob Device noch sichtbar
|
||||
sleep 3 # Kurze Wartezeit für System-Update
|
||||
|
||||
if [ -b "$device_base" ]; then
|
||||
log_warning "Device noch im System sichtbar: $device_base"
|
||||
log_message "Device kann möglicherweise manuell entfernt werden"
|
||||
else
|
||||
log_success "Device nicht mehr im System sichtbar"
|
||||
fi
|
||||
|
||||
log_success "Post-Eject Validierung abgeschlossen"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Safe-Eject Status anzeigen
|
||||
show_eject_status() {
|
||||
echo ""
|
||||
echo "=== Safe-Eject Status ==="
|
||||
|
||||
if mountpoint -q "$MOUNT_POINT"; then
|
||||
mounted_device=$(df "$MOUNT_POINT" | tail -1 | awk '{print $1}')
|
||||
device_base=$(echo "$mounted_device" | sed 's/[0-9]*$//')
|
||||
|
||||
echo "✓ Gemountetes Device: $mounted_device"
|
||||
echo "✓ Hardware Device: $device_base"
|
||||
|
||||
# USB-Status prüfen
|
||||
if lsblk -o TRAN "$device_base" 2>/dev/null | grep -q usb; then
|
||||
echo "✓ USB-Device: Ja"
|
||||
echo "✓ Safe-Eject: Verfügbar"
|
||||
else
|
||||
echo "✗ USB-Device: Nein"
|
||||
echo "✗ Safe-Eject: Nicht verfügbar"
|
||||
fi
|
||||
|
||||
# Aktive Prozesse prüfen
|
||||
active_count=$(lsof "$MOUNT_POINT" 2>/dev/null | wc -l)
|
||||
if [ "$active_count" -gt 0 ]; then
|
||||
echo "! Aktive Prozesse: $active_count"
|
||||
else
|
||||
echo "✓ Aktive Prozesse: Keine"
|
||||
fi
|
||||
|
||||
else
|
||||
echo "✗ Kein Device gemountet"
|
||||
echo "✗ Safe-Eject: Nicht erforderlich"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Hauptfunktion Safe-Eject
|
||||
safe_eject_main() {
|
||||
echo "=== USB-C SSD Safe-Eject ==="
|
||||
echo "Version: 1.0"
|
||||
echo ""
|
||||
|
||||
# Pre-Validierung
|
||||
device=$(validate_pre_eject)
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "=== Safe-Eject Prozess gestartet für: $device ==="
|
||||
echo ""
|
||||
|
||||
# Aktive Prozesse prüfen
|
||||
if ! check_active_processes "$device"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Vollständiger Sync
|
||||
perform_full_sync
|
||||
|
||||
# Unmount
|
||||
if ! perform_unmount "$device"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Hardware-Eject
|
||||
perform_hardware_eject "$device"
|
||||
|
||||
# Post-Validierung
|
||||
validate_post_eject "$device"
|
||||
|
||||
echo ""
|
||||
echo "=== Safe-Eject abgeschlossen ==="
|
||||
echo "USB-C SSD kann jetzt sicher entfernt werden."
|
||||
echo ""
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Hauptfunktion
|
||||
main() {
|
||||
case "${1:-eject}" in
|
||||
"eject")
|
||||
safe_eject_main
|
||||
;;
|
||||
"status")
|
||||
show_eject_status
|
||||
;;
|
||||
*)
|
||||
echo "Verwendung: $0 {eject|status}"
|
||||
echo ""
|
||||
echo "Befehle:"
|
||||
echo " eject - Sichere SSD-Entfernung durchführen"
|
||||
echo " status - Safe-Eject Status anzeigen"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Script ausführen
|
||||
main "$@"
|
Reference in New Issue
Block a user