Rendere una directory protetta da 'rm -rf'


9

Ho appena perso alcuni dati nella cartella A che si trovava nella cartella B dopo averlo fatto rm -rf B. Prima che potessi capire cosa avevo fatto, era tutto finito. Ora che ho imparato una lezione, desidero rendere parte della mia cartella idiota per evitare la prossima volta che faccio qualcosa di simile e voglio uccidermi.

Un modo in cui riesco a pensare è scrivere una funzione bash e alias rm. Questa funzione cercherà in ogni sottocartella un file nascosto come .dontdelete. Una volta trovato, mi chiederebbe se voglio davvero continuare. Non riesco a fare è protetto da scrittura poiché esiste un processo che scrive costantemente in questa cartella. C'è un modo migliore per farlo?


2
Hai provato alias rma rm -i:> -i prompt prima di ogni rimozione o> -I prompt una volta prima di rimuovere più di tre file o durante la rimozione ricorsiva. Meno invadente di -i, pur offrendo protezione contro la maggior parte degli errori Puoi scrivere a quelli con altre bandiere in qualsiasi momento.
IBr

2
Check outsafe-rm
sr_

Ci sono circa una dozzina di modi per farlo. Avrai bisogno di approfondire il tuo ambiente.
Ignacio Vazquez-Abrams,


Un'altra idea è quella di alias in una funzione che lo sposta in una determinata cartella e quindi crea un cronjob che viene eseguito tmpwatchper eliminare i file da questa cartella ogni ora.
Bratchley,

Risposte:


14

Nella ricerca della tua domanda mi sono imbattuto in questa tecnica che potrebbe aiutarti in futuro.

Apparentemente puoi toccare un file nella directory in questo modo:

touch -- -i

Ora quando esegui il comando rm -fr *in una directory dove -iè presente ti verrà presentato il prompt interattivo da rm.

$ ls
file1  file2  file3  file4  file5  -i

$ rm -fr *
rm: remove regular empty file `file1'? n
rm: remove regular empty file `file2'? n
rm: remove regular empty file `file3'? n
rm: remove regular empty file `file4'? n
rm: remove regular empty file `file5'? n

La stessa cosa può essere raggiunta semplicemente lasciando un alias in atto per rmfare sempre rm -i. Questo può diventare fastidioso. Così spesso quello che ho visto è avere questo alias in atto, e quindi disabilitarlo quando vuoi veramente cancellare senza essere richiesto.

alias rm='rm -i'

Ora nelle directory verrai accolto in questo modo:

$ ls
file1  file2  file3  file4  file5

$ rm -r *
rm: remove regular empty file `file1'?

Per sostituire l'alias:

$ \rm -r *

Questo comunque non si ferma a rm -fr. Ma ti fornisce una certa protezione.

Riferimenti


1
Questa è una soluzione piacevole ed elegante che funziona bene se si desidera / è necessario proteggere solo un piccolo set di directory. E potrei essere vecchio stile, ma vivo ancora con l'impressione che se dici --forcequalcosa, lo intendi davvero.
un CVn

Si noti inoltre che rm -I(maiuscolo i) potrebbe essere utile in un alias, in quanto è un po 'meno invadente (secondo la pagina man, viene richiesto solo se si rimuovono più di tre file o in modo ricorsivo).
un CVn

Nota che il touch ./-itrucco funziona solo con GNU rme solo se la variabile POSIXLY_CORRECT non è impostata (i comandi POSIX non riconoscono le opzioni dopo gli argomenti).
Stéphane Chazelas,

5

Molte possibilità:

  • alias rm='rm -i'- chiederà rm - a meno che non specifichi -f...
  • chmod -w dir - protegge i file direttamente in quella directory.
  • chattr +i se lo intendi davvero
  • scrivi il tuo wrapper intorno a rm
  • eccetera...

Ma un modo migliore è probabilmente quello di avere un buon backup e conservare dati importanti in un qualche tipo di controllo della versione (come git), che porta anche molti altri vantaggi.


1
Sono venuto qui per menzionarlo. Suggerirei chattr + i per renderlo completamente sicuro.
JZeolla,

Ho già r aliasing rm -ima, come ci si aspetterebbe, non funziona con l' -fopzione. Uso git per molti altri scopi, ma cosa succede se faccio accidentalmente anche rm -rf *in git?
Dilawar,

Con git, se rimuovi solo una sottodirectory puoi facilmente ripristinarla dal tuo repository locale. Se rimuovi l'intero repository, puoi semplicemente clonarlo di nuovo, dato che lo hai già spostato in un altro posto.
michas,

1

Utilizzare un software di controllo versione come gitincapsulare i progetti.

Finché non si elimina un intero progetto, è necessario digitare intenzionalmente rm -rf .*per rimuovere la .gitdirectory e perdere tutti i dati necessari per un rollback.

Questo ha l'ulteriore vantaggio di poter trasferire i backup delle tue cose su un server remoto come github o bitbucket.


1

Ecco come rm -rf dirfunziona:

  1. Si apre dired elenca il suo contenuto.
  2. Per ogni voce, se si tratta di una directory, ripetere la stessa procedura per essa, in caso contrario, chiamarla unlink.

Se fosse possibile, per l'elenco delle directory, restituire prima un nome file speciale e se si potesse causare la morte di un processo che esegue un unlinkfile su quel file, ciò risolverebbe il problema. Ciò potrebbe essere fatto usando un filesystem con fusibili.

Ad esempio, potresti adattare l' loopback.plesempio dal modulo perl Fuse che implementa semplicemente un filesystem fittizio che è solo un pass-through a un vero file system sottostante (vedi anche la patch sotto):

  • quando si elenca una directory, se contiene una voce denominata .{{do-not-delete}}., anteporre l'elenco delle voci con due file: .{{do-not-delete}}!errore.{{do-not-delete}}!kill
  • quando si tenta unlinkil primo, restituire il EPERMcodice in modo che rmvisualizzi un messaggio di errore
  • quando si tenta unlinkil secondo, il processo viene ucciso.

$ ls -Ff dir/test
./  .{{do-not-delete}}.  foo/  ../  bar
$ ./rm-rf-killer dir
$ ls -Ff dir/test
.{{do-not-delete}}!error  .{{do-not-delete}}!kill  ./  .{{do-not-delete}}.   foo/  ../  bar
$ rm -rf dir/test
rm: cannot remove `dir/test/.{{do-not-delete}}!error': Operation not permitted
zsh: terminated  rm -rf dir/test
$ ls -Ff dir/test
.{{do-not-delete}}!error  .{{do-not-delete}}!kill  ./  .{{do-not-delete}}.   foo/  ../  bar

Qui una patch da applicare in cima a quello loopback.plad esempio come una prova di concetto:

--- loopback.pl 2013-06-03 22:35:00.577316063 +0100
+++ rm-rf-killer    2013-06-03 22:33:41.523328427 +0100
@@ -7,2 +7,4 @@
 my $has_threads = 0;
+my $flag = ".{{do-not-delete}}";
+
 eval {
@@ -42,3 +44,4 @@

-use blib;
+#use blib;
+use File::Basename;
 use Fuse;
@@ -49,3 +52,3 @@

-my %extraopts = ( 'threaded' => 0, 'debug' => 0 );
+my %extraopts = ( 'threaded' => 0, 'debug' => 0, 'mountopts' => 'nonempty' );
 my($use_real_statfs, $pidfile);
@@ -64,3 +67,7 @@

-sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
+sub fixup {
+    my $f = shift;
+    $f =~ s#(/\Q$flag\E)!(error|kill)$#$1.#s;
+    return ".$f";
+}

@@ -78,3 +85,9 @@
 }
-    my (@files) = readdir(DIRHANDLE);
+    my @files;
+    
+    while (my $f = readdir(DIRHANDLE)) {
+        unshift @files, "$flag!error", "$flag!kill"
+            if ($f eq "$flag.");
+        push @files, $f;
+    }
 closedir(DIRHANDLE);
@@ -121,3 +134,12 @@
 sub x_readlink { return readlink(fixup(shift));         }
-sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
+sub x_unlink   {
+    my $f = shift;
+    if (basename($f) eq "$flag!error") {return -EPERM()}
+    if (basename($f) eq "$flag!kill") {
+        my $caller_pid = Fuse::fuse_get_context()->{"pid"};
+        kill("TERM", $caller_pid);
+        return -EPERM();
+    }
+    return unlink(".$f") ? 0 : -$!;
+}

@@ -203,3 +225,2 @@
 sub daemonize {
-    chdir("/") || die "can't chdir to /: $!";
 open(STDIN, "< /dev/null") || die "can't read /dev/null: $!";
@@ -236,2 +257,3 @@

+chdir($mountpoint) or die("chdir: $!");
 daemonize();
@@ -239,3 +261,3 @@
 Fuse::main(
-    'mountpoint'    => $mountpoint,
+    'mountpoint'    => '.',
 'getattr'       => 'main::x_getattr',

-1

Ho creato uno script per semplificare questo compito. Lo script della shell modifica l'autorizzazione in lettura / scrittura e il flag chattr di un determinato elenco di cartelle in modo interattivo, senza richiedere la password di root. Puoi scaricare il file zip dal link indicato di seguito.

https://drive.google.com/file/d/0B_3UYBZy2FVsMVpBSWdSWnFBYk0/edit?usp=sharing

Ho anche incluso lo script di installazione per facilitare l'installazione. Le istruzioni sono incluse nel file zip.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.