Apakah perintah dirantai atom?

8

Jika ada proses terus menulis ke file, dan saya ingin mengambil kendali file dengan root, saya bisa melakukan sesuatu seperti ini:

sudo rm somefile; sudo touch somefile

Apakah mungkin untuk proses penambahan untuk menambahkan file di antara kedua perintah ini? Jika demikian, adakah cara untuk memastikan bahwa tidak ada perintah lain yang dijalankan di antaranya?

Darth Egregious
sumber
4
Ini mungkin masalah XY . Bisakah Anda menjelaskan masalah mendasar yang ingin Anda selesaikan?
Nate Eldredge
1
@NateEldredge: Sama sekali tidak. Saya dapat memahami mengapa tampaknya seperti itu berdasarkan hipotesis saya yang dibuat-buat. Bahkan tidak punya masalah. Hanya penasaran.
Darth Egregious
5
Proses ini sebenarnya mungkin akan terus menulis ke file yang dihapus dan bahkan tidak mencoba untuk membuka yang baru.
Random832
Asumsi saya dalam hipotesis ternyata sedikit salah, tapi saya kira Anda bisa mengubah "tambahkan" menjadi "terbuka" atau "sentuh" ​​dan itu masih masuk akal.
Darth Egregious

Jawaban:

12

Baris perintah dirantai pada dasarnya adalah skrip shell kecil; itu akan menjalankan perintah pertama menggunakan prosedur fork + exec yang biasa, tunggu sampai keluar, kemudian jalankan perintah kedua dengan cara yang sama. Di antara kedua perintah tersebut, ada beberapa waktu arbitrer yang digunakan oleh shell dalam pembukuan dan pemrosesan, di mana multiprocessing biasa terjadi dan proses-proses lain yang sewenang-wenang dapat melakukan hal-hal lain yang sewenang-wenang. Jadi jawabannya adalah 'tidak'. (Jika Anda benar-benar melakukan ini, Anda akan menemukan bahwa entri direktori untuk somefilemenghilang, tetapi file itu sendiri tetap (karena dibuka oleh suatu proses) sampai ditutup. Ruang disk yang digunakan oleh file tidak akan direklamasi sampai itu terjadi. Sementara itu , touchperintah akan membuat file baru yang tidak terkait dengan nama dan jalur yang sama.)

Jika Anda ingin mengubah kepemilikan file menjadi root, lakukan saja sudo chown root:root somefile(meskipun saya tidak yakin bagaimana itu akan mempengaruhi proses dengan filehandhandle terbuka untuk itu). Jika Anda ingin menghancurkan konten file saat ini, coba truncate -s 0 somefile(proses yang berjalan akan terus menambahkan file yang sekarang kosong). Jika itu hal lain, mungkin perjelas apa yang ingin Anda lakukan.

Tom Hunt
sumber
Terima kasih tom. Saya tidak begitu peduli dengan situasi hipotetis saya. Tadinya hanya bertanya-tanya apakah melakukan sesuatu seperti ini adalah mungkin.
Darth Egregious
Mengenai pertanyaan umum, saya tidak berpikir benar-benar ada cara untuk memastikan atomicity dalam skrip shell. Anda dapat menggunakan kunci penguncian dan semacamnya untuk memastikan bahwa dua proses kerja sama tidak saling menginjak, dan Anda dapat menggunakan izin untuk memastikan bahwa proses sewenang-wenang tidak dapat menginjak pekerjaan Anda. Tetapi mencegah hal lain dari menjalankan akan sangat mengacaukan dengan multiprocessing kernel; Saya tidak berpikir kode cincin-3 bisa melakukan itu sama sekali.
Tom Hunt
Anda dapat menggunakan kunci file wajib jika diaktifkan dan tersedia di sistem file Anda.
roaima
5
chowning somefile tidak akan memengaruhi proses yang memiliki pegangan file ke somefile.
PSkocik
Misalnya, Anda bisa melakukannya exec 3>somefile; sudo chmod 0600 somefile; echo hello world >&3; sudo cat somefile; exec 3>&-.
PSkocik
6

Tidak. rmPerintah yang diikuti oleh touchperintah sama sekali bukan atom. Ini akan menjadi waktu yang lama antara dua perintah - mungkin dalam kisaran milidetik. Banyak yang bisa terjadi selama waktu itu. Jika Anda kurang beruntung, kredensial sudo Anda bahkan mungkin kedaluwarsa.

Satu program yang memanggil unlinkdan openmemanggil akan meninggalkan jendela yang jauh lebih pendek untuk balapan, tetapi itu masih bisa terjadi.

Pendekatan yang lebih aman adalah membuat file baru dengan nama sementara dan menggunakan renamepanggilan sistem. "Menimpa" nama dengan renamepanggilan sistem dijamin bersifat atomik. Ini dapat dicapai dengan menggunakan touchdan mv.

Tetapi suatu proses yang telah membuka file lama untuk menulis dapat terus menulis lama setelah itu telah dihapus. Ini akan menjadi kasus untuk file yang dihapus menggunakan unlinkdan yang dihapus menggunakan rename.

kasperd
sumber
3

Setelah suatu proses memiliki filehandle terbuka untuk dibaca, tidak masalah apa yang Anda lakukan dengan kepemilikan atau izin: proses tersebut dapat terus mengakses file. Anda bahkan dapat menghapus file dan prosesnya akan dapat terus mengaksesnya melalui filehandle.

Pertimbangkan izin untuk menjadi gerbang kontrol untuk mendapatkan filehandle.

Jika Anda ingin membuat file secara atom, daripada melakukan ini:

sudo rm somefile
sudo touch somefile

Anda dapat mempertimbangkan ini:

sudo touch anotherfile
sudo perl -e "rename 'anotherfile', 'somefile'"

yang secara atom akan diganti somefiledengan anotherfile. (Saya lebih suka menggunakan mv -ftetapi saya tidak dapat menemukan pernyataan yang menjamin ini panggilan rename(2)sistem panggilan.


Mungkin Anda dapat memperbarui Pertanyaan Anda untuk menjelaskan apa yang Anda maksud dengan "mengendalikan file". Anda mungkin memiliki Masalah XY di sini.

roaima
sumber
Gunakan mv -funtuk mendapatkan rename(2)panggilan sistem. Anda benar lntidak akan melakukannya, karena selalu menggunakan link(2)system call, yang tidak bisa diganti secara atom. ln -flakukan saja unlink(2)pada target pertama.
Peter Cordes
@PeterCordes ah ya tentu saja, terima kasih. Saya punya lndi otak. Saya tidak yakin bagaimana mendapatkan rename(2)jaminan untuk terlibat dan sudah terlambat untuk menggali lebih jauh
roaima
POSIX menjamin bahwa mv"akan melakukan tindakan yang setara dengan" rename(old, new). pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html . mv -fbertindak seperti mv -ijika tujuan tidak dapat ditulisi, tetapi tidak seperti cp -fatau di ln -fmana ia akan memutuskan tautan terlebih dahulu.
Peter Cordes
2

Tidak tapi

sudo rm somefile; sudo touch somefile

aman di sebagian besar situasi.

Sebagian besar proses membuka file dan kemudian menggunakan deskriptor file yang diperoleh untuk mengakses konten file.

Jika suatu proses membuka file tertentu, dalam sh:

 exec 3>somefile

Kemudian proses lain bebas untuk membatalkan tautan (= menghapus) file seseorang dan file yang diarsipkan di mana file dibuka oleh proses pertama (3 dalam kasus ini) akan terus merujuk ke konten asli file somefile, yang sekarang menjadi file dalam limbo.

sudo touch somefile

akan membuat file baru yang tidak terkait dan semua proses yang lama dibuka lama dan sekarang hanya menggunakan file yang diarsipkan untuk merujuknya tidak akan terpengaruh karena mereka merujuk ke file yang berbeda - file yang sekarang dalam limbo.

Jika proses non-root berusaha untuk merujuk ke file tertentu dengan nama, mereka akan mendapatkan kesalahan EPERM, karena file baru milik root.

Jika Anda ingin mencegah beberapa proses di bawah pengguna yang sama (misalnya, root) dari merusak file, linux memiliki penguncian file wajib dan penasihat. Anda dapat menggunakan flockperintah dalam skrip shell untuk mengunci file advisory (lihat halaman manual untuk info lebih lanjut).

PSkocik
sumber