Membuat direktori terlindungi dari 'rm -rf'

9

Saya baru saja kehilangan beberapa data di folder A yang ada di dalam folder B setelah melakukan rm -rf B. Sebelum saya menyadari apa yang telah saya lakukan, semuanya sudah berakhir. Sekarang sebuah pelajaran telah dipelajari, saya ingin membuat beberapa dari folder saya idiot-proof untuk menghindari waktu berikutnya ketika saya melakukan sesuatu yang serupa dan ingin bunuh diri.

Salah satu cara yang dapat saya pikirkan adalah menulis fungsi bash dan menambahkannya ke rm. Fungsi ini akan melihat ke setiap sub-folder untuk file tersembunyi seperti .dontdelete. Ketika ditemukan, ia akan bertanya apakah saya benar-benar ingin melanjutkan. Saya tidak dapat membuatnya dilindungi dari penulisan karena ada proses yang terus-menerus menulis ke folder ini. Apakah ada cara yang lebih baik untuk melakukannya?

Dilawar
sumber
2
Apakah Anda mencoba alias rmuntuk rm -i:> -i prompt sebelum setiap penghapusan atau> -saya minta sekali sebelum menghapus lebih dari tiga file, atau ketika menghapus secara rekursif. Tidak terlalu mengganggu daripada -i, sambil tetap memberikan perlindungan terhadap sebagian besar kesalahan. Anda dapat menuliskannya dengan flag lain kapan saja.
IBr
2
Lihatsafe-rm
sr_
Ada sekitar selusin cara untuk melakukannya. Anda harus lebih detail tentang lingkungan Anda.
Ignacio Vazquez-Abrams
Gagasan lain adalah dengan menambahkannya ke fungsi yang hanya memindahkannya ke folder tertentu dan kemudian membuat cronjob yang dijalankan tmpwatchuntuk menghapus file dari folder ini setiap jam.
Bratchley

Jawaban:

14

Dalam meneliti pertanyaan Anda, saya menemukan teknik ini yang mungkin membantu Anda di masa depan.

Anda tampaknya dapat menyentuh file di direktori seperti ini:

touch -- -i

Sekarang ketika Anda menjalankan perintah rm -fr *di direktori tempat -ihadir Anda akan disajikan dengan prompt interaktif dari 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

Hal yang sama dapat dicapai dengan hanya meninggalkan alias di tempat rmagar selalu dilakukan rm -i. Ini bisa mengganggu. Seringkali yang saya lihat dilakukan adalah menempatkan alias ini di tempatnya, dan kemudian menonaktifkannya ketika Anda benar-benar ingin menghapus tanpa diminta.

alias rm='rm -i'

Sekarang di direktori Anda akan disambut seperti ini:

$ ls
file1  file2  file3  file4  file5

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

Untuk mengganti alias:

$ \rm -r *

Namun ini masih tidak berhenti rm -fr. Tapi itu memberi Anda perlindungan.

Referensi

slm
sumber
1
Ini adalah solusi yang bagus dan elegan yang berfungsi dengan baik jika Anda hanya ingin / perlu melindungi sekumpulan direktori kecil. Dan saya mungkin kuno tetapi saya masih hidup di bawah kesan bahwa jika Anda mengatakan --forcesesuatu, Anda benar-benar bersungguh-sungguh.
CVn
Perhatikan juga bahwa rm -I(huruf besar i) mungkin berguna dalam alias, karena sedikit kurang mengganggu (menurut halaman manual, hanya meminta jika Anda menghapus lebih dari tiga file atau secara rekursif).
CVn
Perhatikan bahwa touch ./-itrik ini hanya berfungsi dengan GNU rmdan hanya jika variabel POSIXLY_CORRECT tidak disetel (perintah POSIX tidak mengenali opsi setelah argumen).
Stéphane Chazelas
5

Banyak kemungkinan:

  • alias rm='rm -i'- rm akan bertanya - kecuali jika Anda menentukan -f...
  • chmod -w dir - melindungi file secara langsung di direktori itu.
  • chattr +i jika Anda benar-benar bersungguh-sungguh
  • tulis pembungkus Anda sendiri di sekitar rm
  • dll ...

Tetapi cara yang lebih baik mungkin adalah memiliki cadangan yang baik dan menyimpan data penting dalam beberapa jenis kontrol versi (seperti git), yang juga membawa banyak keuntungan lainnya.

michas
sumber
1
Datang ke sini untuk menyebutkan ini. Saya menyarankan chattr + i untuk membuatnya sepenuhnya aman.
JZeolla
Saya sudah memiliki rm alias rm -itetapi seperti yang diharapkan, itu tidak bekerja dengan -fopsi. Saya menggunakan git untuk banyak tujuan lain, tetapi bagaimana jika saya secara tidak sengaja juga melakukannya rm -rf *di git?
Dilawar
Dengan git, jika Anda hanya menghapus subdirektori, Anda dapat dengan mudah mengembalikannya dari repositori lokal Anda. Jika Anda menghapus seluruh repositori, Anda dapat mengkloningnya kembali - karena Anda mendorongnya ke tempat lain sebelumnya.
michas
1

Gunakan perangkat lunak kontrol versi ingin gitmerangkum proyek Anda.

Selama Anda tidak menghapus seluruh proyek, Anda harus mengetik dengan sengaja rm -rf .*untuk menghapus .gitdirektori dan kehilangan semua data yang diperlukan untuk rollback.

Ini memiliki manfaat tambahan bahwa Anda dapat mendorong cadangan barang-barang Anda ke server jarak jauh seperti github atau bitbucket.

JoshRagem
sumber
1

Begini cara rm -rf dirkerjanya:

  1. Itu terbuka dir, dan daftar isinya.
  2. Untuk setiap entri, jika itu adalah direktori, ulangi proses yang sama untuk itu, jika tidak, panggil unlinksaja.

Jika Anda dapat, untuk daftar direktori, kembalikan nama file khusus terlebih dahulu, dan jika Anda dapat menyebabkan proses melakukan unlinkpada file itu mati, itu akan menyelesaikan masalah. Itu bisa dilakukan dengan menggunakan sistem file sekering.

Sebagai contoh, Anda bisa mengadaptasi loopback.plcontoh dari modul Fuse perl yang hanya mengimplementasikan sistem file dummy yang hanya pass-through ke sistem file nyata di bawahnya seperti itu (lihat juga tambalan di bawah):

  • saat mendaftar direktori, jika berisi entri bernama .{{do-not-delete}}., tambahkan daftar entri dengan dua file: .{{do-not-delete}}!errordan.{{do-not-delete}}!kill
  • saat mencoba unlinkyang pertama, kembalikan EPERMkode sehingga rmmenampilkan pesan kesalahan
  • ketika mencoba unlinkyang kedua, prosesnya terbunuh.

$ 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

Di sini tambalan untuk diterapkan di atas loopback.plcontoh itu sebagai bukti konsep:

--- 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',
Stéphane Chazelas
sumber
-1

Saya telah membuat skrip untuk mempermudah tugas ini. Script shell memodifikasi izin baca / tulis dan flag chattr dari daftar folder yang diberikan secara interaktif, tanpa meminta kata sandi root. Anda dapat mengunduh file zip dari tautan yang diberikan di bawah ini.

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

Saya juga menyertakan skrip instalasi untuk mempermudah pengaturan. Instruksi terlampir dalam file zip.

Liju G. Chacko
sumber