Was rm schon verweigert und was nicht
GNU rm verweigert rm -rf / von Haus aus. Das schützt genau einen Pfad. Die üblichen Unfälle sehen anders aus:
rm -rf /*: Die Shell erweitert zuerst den Stern,rmbekommt also/bin,/etcund den Rest, und keiner davon ist/.rm -rf /var/app /*: Ein verirrtes Leerzeichen setzt das ganze System auf die Liste.- Eine leere Variable in einem Skript:
rm -rf "$DIR"/*wird zurm -rf /*. - Der richtige Befehl im falschen Terminal, auf einem Server, den Sie für Staging hielten.
--preserve-root=all geht einen Schritt weiter und verweigert jeden Ordner, der auf einer anderen Platte liegt als sein übergeordneter Ordner, etwa ein eingehängtes Volume:
rm: skipping '/dev/shm', since it's on a different device
rm: and --preserve-root=all is in effect
Gewohnheiten wie einen Glob vor dem Löschen mit echo aufzulisten finden Sie unter wie Sie Fehler auf Produktionsservern vermeiden.
Interaktives rm einmal nachfragen lassen
Schreiben Sie diese zwei Zeilen auf dem Server in ~/.bashrc und in /root/.bashrc:
alias rm='rm -I --preserve-root=all'
alias sudo='sudo '
-I fragt einmal vor einem rekursiven Löschen oder vor dem Entfernen von mehr als drei Dateien. Alles außer y entfernt nichts. Das Leerzeichen am Ende des sudo-Alias sagt bash, dass es auch das nächste Wort als Alias erweitern soll, also fragt auch sudo rm:
$ sudo rm /tmp/s/*
rm: remove 4 arguments? n
zsh fragt von sich aus vor rm * und rm pfad/*, außer RM_STAR_SILENT ist gesetzt:
zsh: sure you want to delete all 2 files in /tmp/z [yn]? n
Aliase gelten nur in interaktiven Shells. Skripte, Cron-Jobs und ssh server 'rm ...' nutzen das echte rm, und \rm oder command rm umgehen den Alias absichtlich. Verzichten Sie auf alias rm='rm -i': Eine Frage pro Datei gewöhnt Leute daran, -f zu tippen.
safe-rm: Pfade, die rm überspringt
safe-rm setzt einen Wrapper vor rm, der jeden Pfad auf einer Schutzliste überspringt. Unter Debian und Ubuntu:
sudo apt install safe-rm
echo '/srv/app/shared' | sudo tee -a /etc/safe-rm.conf
Die Liste enthält bereits Systemordner wie /etc, /usr und /var. Unser Test:
$ rm -rf /srv/app/shared
safe-rm: Skipping /srv/app/shared.
Kennen Sie die Grenzen, bevor Sie sich darauf verlassen:
- Es schützt den eingetragenen Pfad, nicht seinen Inhalt.
rm -rf /srv/app/shared/*hat den Ordner trotzdem geleert. Eine Zeile wie/srv/data/*schützt jeden Eintrag direkt unter/srv/data. - Es endet mit 0, auch wenn es etwas übersprungen hat, ein Skript merkt es also nicht.
- Das Paket ergänzt
PATHin/etc/profile.dum seinen Ordner, es wirkt also in Login-Shells und mitsudo -i.sudo rmnutzt den eigenensecure_pathvon sudo und lief in unserem Test mit dem echtenrm, ebensossh server 'rm ...'.
Variablen in Skripten absichern
Die meisten Katastrophen in Skripten kommen von einer leeren oder nicht gesetzten Variable. Halten Sie das Skript an, bevor es rm erreicht:
#!/usr/bin/env bash
set -euo pipefail
rm -rf -- "${BUILD_DIR:?}/"
s.sh: line 3: BUILD_DIR: parameter null or not set
${BUILD_DIR:?} bricht mit einem Fehler ab, wenn die Variable leer ist oder fehlt, und set -u tut dasselbe für jede nicht gesetzte Variable im Skript. -- beendet die Optionen, sodass eine Datei namens -rf als Datei behandelt wird.
Rechte und unveränderliche Dateien
Der stärkste Schutz ist, gar nicht löschen zu können. Arbeiten Sie als normaler Benutzer und nutzen Sie sudo nur für die Befehle, die es brauchen, dann erreicht ein Ausrutscher im Home-Ordner nicht das System. Siehe wie Sie einen SSH-Benutzer mit sudo anlegen.
Für Dateien, die sich selbst für root nicht ändern dürfen, setzen Sie das Immutable-Flag, auf ext4 und anderen Dateisystemen, die es unterstützen:
sudo chattr +i /etc/app/config.yml
lsattr /etc/app/config.yml
----i---------e------- /etc/app/config.yml
rm: cannot remove '/etc/app/config.yml': Operation not permitted
Derselbe Fehler stoppte auch rm -rf auf dem umgebenden Ordner. Entfernen Sie das Flag mit sudo chattr -i vor einer geplanten Änderung. Auch Updates und Editoren können die Datei nicht schreiben, setzen Sie das Flag also nur dort, wo es wirklich nötig ist.
Ein Papierkorb statt rm
Wenn Sie von Hand aufräumen, verschieben Sie Dateien lieber in einen Papierkorb. trash-cli nutzt denselben Papierkorb wie der Linux-Desktop:
sudo apt install trash-cli
trash-put old-release/
trash-list
trash-restore
trash-empty 30
trash-restore fragt, welcher Eintrag zurück soll. trash-empty 30 entfernt, was länger als 30 Tage im Papierkorb liegt, passend für einen Cron-Job. Bis dahin belegen die Dateien weiter Speicherplatz. Machen Sie rm nicht zum Alias für trash-put: Die Optionen unterscheiden sich, und die Gewohnheit versagt auf Servern ohne das Werkzeug.
Snapshots, Backups und wenn es schon passiert ist
Jede Schicht oben lässt sich umgehen. Einen Snapshot löscht rm nicht. Legen Sie vor riskanter Arbeit einen an: zfs snapshot pool/data@before-cleanup unter ZFS, btrfs subvolume snapshot -r unter btrfs, lvcreate --snapshot mit LVM oder einen Volume-Snapshot in der Konsole Ihres Cloud-Anbieters. Kopieren Sie Backups auf einen anderen Rechner, etwa mit rsync über SSH, und testen Sie ab und zu eine Wiederherstellung.
Sind Dateien schon weg, schreiben Sie nichts mehr auf diese Platte: Neue Daten können überschreiben, was ein Rettungswerkzeug noch finden könnte. Stellen Sie dann aus Snapshot oder Backup wieder her. Ein Fall lässt sich sofort retten: eine Datei, die ein laufendes Programm noch geöffnet hat. Finden Sie sie und kopieren Sie sie zurück, bevor das Programm endet:
lsof +L1
cp /proc/374/fd/3 /root/data.recovered
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
tail 374 root 3r REG 0,186 2 0 12873355 /srv/data.txt (deleted)
Die Zahl nach /proc/ ist die PID, die nach fd/ die Zahl aus der Spalte FD ohne ihren Buchstaben.
Fragen
Funktioniert rm -rf / unter Linux noch?
Mit GNU rm nicht: Es verweigert /, außer Sie geben --no-preserve-root an. rm -rf /* erweitert die Shell aber zu /bin, /etc und dem Rest, und das wird nicht verweigert.
Kann ich rm -rf rückgängig machen?
Nicht mit rm selbst. Stellen Sie aus einem Snapshot oder Backup wieder her. Eine Datei, die ein laufendes Programm noch geöffnet hat, lässt sich aus /proc/PID/fd zurückkopieren, bis das Programm sie schließt.
Ist alias rm='rm -i' eine gute Idee?
Es fragt bei jeder Datei, also gewöhnt man sich an, ohne Lesen mit y zu antworten oder -f anzuhängen. rm -I fragt einmal, bei drei oder mehr Dateien oder beim rekursiven Löschen, und die Frage behält ihren Sinn.
Schützt safe-rm auch die Dateien in einem Ordner?
Nein. Es überspringt die Pfade aus seiner Konfiguration. rm -rf /srv/app/shared/* leert einen geschützten Ordner /srv/app/shared trotzdem, außer die Einträge darin stehen ebenfalls in der Liste, zum Beispiel mit /srv/app/shared/*.
Quellen
- GNU-coreutils-Handbuch: Aufruf von rm
- Projekt safe-rm
- chattr(1), Linux-Handbuch
- Projekt trash-cli
- zsh-Handbuch: RM_STAR_SILENT
- OpenZFS: zfs-snapshot(8)