Tornando um diretório protegido de 'rm -rf'


9

Acabei de perder alguns dados na pasta A, que estava dentro da pasta B depois de fazer rm -rf B. Antes que eu pudesse perceber o que fiz, tudo acabou. Agora que uma lição é aprendida, desejo tornar algumas das minhas pastas à prova de idiotas para evitar uma próxima vez em que fizer algo semelhante e quiser me matar.

Uma maneira de pensar é escrever uma função bash e alias-la rm. Esta função procurará em cada subpasta um arquivo oculto, como .dontdelete. Quando encontrado, perguntaria se eu realmente queria continuar. Eu não posso fazer é protegido contra gravação, pois há um processo que constantemente escreve para esta pasta. Existe alguma maneira melhor de fazer isso?


2
Você tentou o alias rmpara rm -i:> -i solicitar antes de cada remoção ou> -I solicitar uma vez antes de remover mais de três arquivos ou ao remover recursivamente. Menos invasivo que -i, ao mesmo tempo em que protege contra a maioria dos erros Você pode escrever aqueles com outros sinalizadores a qualquer momento.
IBr

2
Confirasafe-rm
sr_

Existem cerca de uma dúzia de maneiras de fazer isso. Você precisará entrar em mais detalhes sobre seu ambiente.
Ignacio Vazquez-Abrams


Outra idéia é aliasá-lo para uma função que apenas o move para uma pasta específica e criar um cronjob que é executado tmpwatchpara excluir arquivos dessa pasta a cada hora.
Bratchley

Respostas:


14

Ao pesquisar sua pergunta, me deparei com essa técnica que pode ajudá-lo no futuro.

Aparentemente, você pode tocar em um arquivo no diretório da seguinte maneira:

touch -- -i

Agora, quando você executa o comando rm -fr *em um diretório em que o -ipresente está presente, será apresentado o prompt interativo de 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

A mesma coisa pode ser alcançada deixando um alias no lugar para rmsempre fazer rm -i. Isso pode ser irritante. Muitas vezes, o que eu vi fazer é ter esse alias no lugar e desativá-lo quando você realmente deseja excluir sem ser solicitado.

alias rm='rm -i'

Agora, nos diretórios, você será recebido assim:

$ ls
file1  file2  file3  file4  file5

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

Para substituir o alias:

$ \rm -r *

Isso ainda não para de rm -frqualquer maneira. Mas isso fornece alguma proteção.

Referências


1
Essa é uma solução agradável e elegante que funciona bem se você deseja / precisa proteger apenas um pequeno conjunto de diretórios. E posso ser antiquado, mas ainda tenho a impressão de que, se você diz --forcealgo, realmente está falando sério.
a CVn

Observe também que rm -I(maiúsculas i) pode ser útil em um alias, pois é um pouco menos invasivo (de acordo com a página do manual, somente solicita se você remover mais de três arquivos ou recursivamente).
a CVn

Note que o touch ./-itruque só funciona com o GNU rme somente se a variável POSIXLY_CORRECT não estiver configurada (os comandos POSIX não reconhecem opções após argumentos).
Stéphane Chazelas

5

Muitas possibilidades:

  • alias rm='rm -i'- rm perguntará - a menos que você especifique -f...
  • chmod -w dir - protege os arquivos diretamente nesse diretório.
  • chattr +i se você realmente quer dizer isso
  • escreva seu próprio invólucro em torno da rm
  • etc ...

Mas uma maneira melhor é provavelmente ter um bom backup e manter dados importantes em algum tipo de controle de versão (como git), o que traz muitas outras vantagens também.


1
Vim aqui para mencionar isso. Eu sugeriria o chattr + i para torná-lo totalmente seguro.
JZeolla

Já tenho rm alias para, rm -imas como seria de esperar, ele não funciona com -fopção. Eu uso o git para muitos outros fins, mas e se eu acidentalmente também o fizer rm -rf *?
Dilawar

Com o git, se você remover apenas um subdiretório, poderá restaurá-lo facilmente do seu repositório local. Se você remover o repositório inteiro, poderá simplesmente cloná-lo novamente - desde que você o tenha empurrado para outro lugar antes.
Michas

1

Use um software de controle de versão como gitpara encapsular seus projetos.

Contanto que você não exclua um projeto inteiro, será necessário digitar propositadamente rm -rf .*para remover o .gitdiretório e perder todos os dados necessários para uma reversão.

Isso tem o benefício adicional de poder enviar backups de suas coisas para um servidor remoto como o github ou o bitbucket.


1

Veja como rm -rf dirfunciona:

  1. Ele abre dire lista seu conteúdo.
  2. Para cada entrada, se for um diretório, repita o mesmo processo, se não for, chame unlink-o.

Se você pudesse, para a listagem de diretórios, retornar um nome de arquivo especial primeiro e se pudesse causar unlinka morte de um processo que faz um arquivo nesse arquivo, isso resolveria o problema. Isso pode ser feito usando um sistema de arquivos com fusível.

Por exemplo, você pode adaptar o loopback.plexemplo do módulo perl Fuse, que apenas implementa um sistema de arquivos fictício que é apenas uma passagem para um sistema de arquivos real por baixo (veja também o patch abaixo):

  • ao listar um diretório, se ele contiver uma entrada nomeada .{{do-not-delete}}., anteceda a lista de entradas com dois arquivos: .{{do-not-delete}}!errore.{{do-not-delete}}!kill
  • ao tentar unlinko primeiro, retorne o EPERMcódigo para rmexibir uma mensagem de erro
  • ao tentar unlinko segundo, o processo é interrompido.

$ 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

Aqui, um patch a ser aplicado sobre esse loopback.plexemplo como prova de conceito:

--- 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

Eu criei um script para facilitar essa tarefa. O script shell modifica a permissão de leitura / gravação e o sinalizador chattr de uma determinada lista de pastas de maneira interativa, sem solicitar a senha do root. Você pode fazer o download do arquivo zip no link abaixo.

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

Também incluí o script de instalação para facilitar a instalação. As instruções estão incluídas no arquivo zip.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.