Apa yang menghasilkan pesan "file teks sibuk" di Unix?

137

Operasi apa yang menghasilkan kesalahan "file teks sibuk"? Saya tidak bisa mengatakan dengan tepat.

Saya pikir ini terkait dengan fakta bahwa saya membuat skrip python sementara (menggunakan tempfile) dan menggunakan execl dari itu, tapi saya pikir execl mengubah file yang sedang dijalankan.

Penz
sumber

Jawaban:

130

Kesalahan ini berarti beberapa proses atau pengguna lain mengakses file Anda. Gunakan lsofuntuk memeriksa proses lain apa yang menggunakannya. Anda dapat menggunakan killperintah untuk membunuhnya jika diperlukan.

jaypal singh
sumber
115
The Text file busykesalahan dalam spesifik tentang mencoba untuk memodifikasi executable ketika sedang mengeksekusi. "Teks" di sini merujuk pada fakta bahwa file yang sedang dimodifikasi adalah segmen teks untuk program yang sedang berjalan. Ini adalah kasus yang sangat istimewa, dan bukan yang umum yang tampaknya disarankan oleh jawaban Anda. Meski begitu, jawaban Anda tidak sepenuhnya salah.
ArjunShankar
4
Jawaban dengan komentar itu tampaknya lengkap.
Penz
OP bertanya operasi mana yang menghasilkan kesalahan, bukan untuk penjelasan tentang apa arti kesalahan tersebut.
WonderWorker
Saya pikir fakta bahwa unix menganggap file adalah "file teks" adalah tidak masuk akal, dalam kasus saya itu adalah file biner yang memicu kesalahan ini.
Felipe Valdes
1
@FelipeValdes Namanya historis dari terminologi setengah abad yang lalu. Sebagai contoh, dalam multik segmen teks dari suatu program berbeda dari segmen tautan, dan bahkan orang-orang sebelumnya berbicara tentang teks biner. stackoverflow.com/a/1282540/833300
jma
30

Sudah lama sejak saya melihat pesan itu, tetapi dulu lazim di System V R3 atau sekitar beberapa dekade yang lalu. Saat itu, itu berarti Anda tidak dapat mengubah program yang dapat dieksekusi saat sedang berjalan.

Sebagai contoh, saya sedang membangun sebuah makeworkalike yang disebut rmk, dan setelah beberapa saat itu swalayan. Saya akan menjalankan versi pengembangan dan membuatnya membangun versi baru. Untuk membuatnya bekerja, perlu untuk menggunakan solusi:

gcc -g -Wall -o rmk1 main.o -L. -lrmk -L/Users/jleffler/lib/64 -ljl
if [ -f rmk ] ; then mv rmk rmk2 ; else true; fi ; mv rmk1 rmk

Jadi, untuk menghindari masalah dengan 'file teks sibuk', build membuat file baru rmk1, lalu memindahkan yang lama rmkke rmk2(mengganti nama bukan masalah; membatalkan tautan dulu), lalu memindahkan yang baru dibangun rmk1ke rmk.

Saya belum melihat kesalahan pada sistem modern dalam waktu yang cukup lama ... tapi saya tidak semua yang sering memiliki program membangun kembali diri mereka sendiri.

Jonathan Leffler
sumber
3
Berikut adalah reproducer cepat yang super: echo -e '#include <unistd.h>\nint main(void){sleep (5);return 0;}' > slowprog.c && cc slowprog.c && cp a.out b.out && (./a.out &) ; sleep 1 && cp b.out a.out. Menghasilkan pesan kesalahan "cp: tidak dapat membuat file biasa 'a.out': File teks sibuk" di Fedora saya yang baru.
ArjunShankar
3
Tentu saja, jawaban ini benar dan mendapat +1. Anda mungkin ingin menghapus penafian "Sudah lama".
ArjunShankar
@ArjunShankar di sini adalah reproduksi C pada Linux modern dengan panggilan sistem "langsung": stackoverflow.com/questions/16764946/... GCC hanya dapat menimpa menjalankan executable saat ini karena jika pertama melakukan secara unlinkdefault.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
14

Ini terjadi ketika Anda mencoba dan menulis ke file yang saat ini sedang dieksekusi oleh kernel, atau mengeksekusi file yang saat ini terbuka untuk ditulis.

Sumber: http://wiki.wlug.org.nz/ETXTBSY

Messa
sumber
6

Contoh reproduksi C POSIX runnable minimal

Saya merekomendasikan untuk memahami API yang mendasarinya untuk melihat dengan lebih baik apa yang sedang terjadi.

sleep.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    sleep(10000);
}

busy.c

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {
    int ret = open("sleep.out", O_WRONLY|O_TRUNC);
    assert(errno == ETXTBSY);
    perror("");
    assert(ret == -1);
}

Kompilasi dan jalankan:

gcc -std=c99 -o sleep.out ./sleep.c
gcc -std=c99 -o busy.out ./busy.c
./sleep.out &
./busy.out 

busy.outmelewati pernyataan, dan perrorkeluaran:

Text file busy

jadi kami menyimpulkan bahwa pesan tersebut di-hardcode dalam glibc itu sendiri.

Kalau tidak:

echo asdf > sleep.out

membuat output Bash:

-bash: sleep.out: Text file busy

Untuk aplikasi yang lebih kompleks, Anda juga dapat mengamatinya dengan strace:

strace ./busy.out

yang mengandung:

openat(AT_FDCWD, "sleep.out", O_WRONLY) = -1 ETXTBSY (Text file busy)

Diuji pada Ubuntu 18.04, kernel Linux 4.15.0.

Kesalahan tidak terjadi jika Anda unlinkterlebih dahulu

notbusy.c:

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void) {
    assert(unlink("sleep.out") == 0);
    assert(open("sleep.out", O_WRONLY|O_CREAT) != -1);
}

Kemudian kompilasi dan jalankan secara analog dengan yang di atas, dan mereka menegaskan lulus.

Ini menjelaskan mengapa ini bekerja untuk program tertentu tetapi tidak untuk yang lain. Misal jika Anda melakukannya:

gcc -std=c99 -o sleep.out ./sleep.c
./sleep.out &
gcc -std=c99 -o sleep.out ./sleep.c

itu tidak menghasilkan kesalahan, meskipun gccpanggilan kedua menulis sleep.out.

Quick stracemenunjukkan bahwa GCC memutuskan tautan terlebih dahulu sebelum menulis:

 strace -f gcc -std=c99 -o sleep.out ./sleep.c |& grep sleep.out

mengandung:

[pid  3992] unlink("sleep.out")         = 0
[pid  3992] openat(AT_FDCWD, "sleep.out", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3

Alasannya tidak gagal adalah bahwa ketika Anda unlinkdan menulis ulang file, itu menciptakan inode baru, dan membuat inode menggantung sementara untuk menjalankan file yang dapat dieksekusi.

Tetapi jika Anda hanya writetanpa unlink, maka itu mencoba untuk menulis ke inode yang dilindungi yang sama dengan menjalankan executable.

POSIX 7 open()

http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

[ETXTBSY]

File tersebut adalah file prosedur murni (teks bersama) yang sedang dieksekusi dan oflag adalah O_WRONLY atau O_RDWR.

man 2 terbuka

ETXTBSY

pathname mengacu pada gambar yang dapat dieksekusi yang sedang dieksekusi dan akses tulis diminta.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
1
Alasan untuk kasus pembatalan tautan adalah bahwa file tersebut tidak lagi dapat diakses dari direktori itu, tetapi inode masih ada dengan refcount> 0. Jika Anda menggunakan kembali namanya, itu kemudian file baru dalam inode baru - sedangkan jika Anda tidak memutuskan tautan terlebih dahulu, Anda sebenarnya mencoba menulis ke inode yang dilindungi.
Penz
@ Penz obrigado atas komentarnya, Leandro. Saya juga bertanya-tanya mengapa, sebaliknya, apakah itu memberikan kesalahan jika Anda mencoba menulis tanpa unlink. Apakah Linux pernah membaca file lebih dari sekali setelah execpanggilan pertama ?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Apa yang menghasilkan ETXTBSY adalah perlindungan inode. Tanpa tautan, tulisan apa pun masuk ke inode yang dilindungi oleh eksekusi file; dengan membatalkan tautan, Anda mendapatkan inode baru yang tidak dilindungi. (tidak yakin "dilindungi" adalah istilah di sini, tapi itulah idenya)
Penz
5

Dalam kasus saya, saya mencoba mengeksekusi file shell (dengan ekstensi .sh) di lingkungan csh, dan saya mendapatkan pesan kesalahan itu.

hanya berlari dengan bash itu berhasil bagiku. Sebagai contoh

bash file.sh

Rafayel Paremuzyan
sumber
1
Apakah ada #!/bin/bashtajuk?
Penz
Ini memiliki tajuk #! / Bin / sh
Rafayel Paremuzyan
Anda mungkin ingin mencoba menggunakan #!/usr/bin/cshatau setara.
Penz
3

Jika mencoba membangun phpredisdi kotak Linux Anda mungkin perlu memberi waktu untuk menyelesaikan memodifikasi izin file, dengan sleepperintah, sebelum menjalankan file:

chmod a+x /usr/bin/php/scripts/phpize \
  && sleep 1 \
  && /usr/bin/php/scripts/phpize
Stephane
sumber
Saya tidak berpikir chmodakan kembali sebelum izin ditetapkan. Itu mungkin masalah sistem file.
Penz
Ini terjadi di dalam gambar Docker sedang dibangun.
Stephane
1
Docker memiliki beberapa driver penyimpanan, saya kira tidak semuanya sempurna.
Penz
Namun, itu adalah petunjuk yang sangat bagus untuk orang yang mengalami masalah ini saat membangun citra buruh pelabuhan.
Maciej Gol
2

Tidak tahu penyebabnya, tetapi saya dapat berkontribusi untuk penyelesaian yang cepat dan mudah.

Saya baru saja mengalami keanehan ini pada CentOS 6 setelah "cat> shScript.sh" (paste, ^ Z) kemudian mengedit file dalam KWrite. Anehnya tidak ada instance yang dapat dilihat (ps -ef) dari eksekusi skrip.

Pekerjaan cepat saya di sekitar adalah hanya untuk "cp shScript.sh shScript2.sh" maka saya dapat menjalankan shScript2.sh. Lalu saya menghapus keduanya. Selesai!

ScottWelker
sumber
Masalah Anda adalah karena Anda ditangguhkan yang catproses. Lain kali gunakan ^ D, bukan ^ Z.
Vladimir Panteleev
Vladimir yang benar. Terima kasih! Itulah yang akan saya lakukan di DOS / CMD prompt. Habbits lama ... belum terjadi sejak :)
ScottWelker
2

Anda mungkin menemukan ini lebih umum di CIFS / jaringan SMB. Windows tidak mengizinkan file untuk ditulis ketika ada sesuatu yang membuka file itu, dan bahkan jika layanan ini bukan Windows (mungkin beberapa produk NAS lainnya), kemungkinan akan mereproduksi perilaku yang sama. Secara potensial, ini mungkin juga merupakan manifestasi dari beberapa masalah NAS mendasar yang secara samar terkait dengan penguncian / replikasi.

Cameron Kerr
sumber
2

Jika Anda menjalankan .sh dari koneksi ssh dengan alat seperti MobaXTerm, dan jika alat tersebut memiliki utilitas autosave untuk mengedit file jarak jauh dari mesin lokal, itu akan mengunci file.

Menutup dan membuka kembali sesi SSH menyelesaikannya.

Poutrathor
sumber
1

Salah satu pengalaman saya:

Saya selalu mengubah pintasan keyboard default Chrome melalui reverse engineering. Setelah modifikasi, saya lupa menutup Chrome dan menjalankan yang berikut:

sudo cp chrome /opt/google/chrome/chrome
cp: cannot create regular file '/opt/google/chrome/chrome': Text file busy

Menggunakan strace, Anda dapat menemukan detail lebih lanjut:

sudo strace cp ./chrome /opt/google/chrome/chrome 2>&1 |grep 'Text file busy'
open("/opt/google/chrome/chrome", O_WRONLY|O_TRUNC) = -1 ETXTBSY (Text file busy)
Firo
sumber
0

Saya menemukan ini di PHP ketika menggunakan fopen()pada file dan kemudian mencoba unlink()sebelum menggunakannya fclose().

Tidak baik:

$handle = fopen('file.txt');
// do something
unlink('file.txt');

Baik:

$handle = fopen('file.txt');
// do something
fclose($handle);
unlink('file.txt');
dtbarne
sumber
Di windows saya kira? Di linux sistem biasanya memungkinkan kita untuk menghapus file yang terbuka - referensi dalam direktori dihilangkan, tetapi data (inode) fred hanya ketika jumlah referensi mencapai 0.
Penz
Tidak, ini ada di Centos.
dtbarne
Mengujinya di Linux 4.7.10 dengan sistem file ext4 dan tidak menghasilkan kesalahan, bekerja seperti yang disebutkan Penz. File berhasil dihapus. Mungkin dtbarne menggunakan beberapa sistem file khusus.
k3a
Sedang menjalankan ini pada gelandangan - mungkin karena itu menjadi folder bersama.
dtbarne
0
root@h1:bin[0]# mount h2:/ /x             
root@h1:bin[0]# cp /usr/bin/cat /x/usr/local/bin/
root@h1:bin[0]# umount /x
...
root@h2:~[0]# /usr/local/bin/cat 
-bash: /usr/local/bin/cat: Text file busy
root@h2:~[126]#

ubuntu 20.04, 5.4.0-40-generic
nfsd problem, after reboot ok
Rustem
sumber
Tolong jangan posting kode hanya sebagai jawaban, tetapi juga berikan penjelasan apa yang kode Anda lakukan dan bagaimana memecahkan masalah pertanyaan. Jawaban dengan penjelasan biasanya lebih bermanfaat dan berkualitas lebih baik, dan lebih cenderung menarik upvotes.
Mark Rotteveel