Unix'te "metin dosyası meşgul" mesajını ne oluşturur?


137

Hangi işlem "metin dosyası meşgul" hatasını oluşturur? Tam olarak söyleyemiyorum.

Sanırım geçici bir python betiği oluşturmam (tempfile kullanarak) ve ondan execl kullanmamla ilgili, ancak execl'nin çalıştırılan dosyayı değiştirdiğini düşünüyorum.

Yanıtlar:


130

Bu hata, başka bir işlemin veya kullanıcının dosyanıza erişmekte olduğu anlamına gelir. lsofBaşka hangi işlemlerin kullandığını kontrol etmek için kullanın . killGerekirse onu öldürmek için komutu kullanabilirsiniz .


115
Özellikle Text file busyhata, çalıştırılırken bir yürütülebilir dosyayı değiştirmeye çalışmakla ilgilidir. Buradaki "Metin", değiştirilmekte olan dosyanın çalışan bir programın metin bölümü olduğu gerçeğini ifade eder . Bu çok özel bir durumdur ve cevabınızın önerdiği genel durum değil. Öyle olsa bile, cevabınız tamamen yanlış değil.
ArjunShankar

4
Yorumla birlikte cevap tamamlanmış görünüyor.
Penz

OP, hatanın ne anlama geldiğinin açıklaması için değil, hangi işlemin hatayı oluşturduğunu sordu.
WonderWorker

Unix'in dosyaların "metin dosyaları" olduğunu varsaymasının mantıksız olduğunu düşünüyorum, benim durumumda bu hataya neden olan ikili bir dosyaydı.
Felipe Valdes

1
@FelipeValdes Adı, yarım asır öncesinin terminolojisine dayanmaktadır. Örneğin, multics'te bir programın metin bölümü bağlantı bölümünden farklıydı ve daha önce insanlar ikili metin hakkında konuşuyordu. stackoverflow.com/a/1282540/833300
jma

30

Bu mesajı görmeyeli epey oldu, ama eskiden System V R3'te ya da birkaç on yıl önce yaygındı. O zamanlar bu, çalıştırılabilir bir programı çalışırken değiştiremeyeceğiniz anlamına geliyordu.

Örneğin ben bir iş makeyapıyordum rmkve bir süre sonra kendi kendini idame ettiriyordum. Geliştirme sürümünü çalıştırır ve yeni bir sürüm oluşturmasını isterdim. Çalışması için geçici çözümü kullanmak gerekiyordu:

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

Yani, 'meşgul metin dosyası' ile sorunları önlemek için, yapı yeni bir dosya oluşturdu rmk1, sonra eski taşındı rmketmek rmk2ve sonra yeni inşa taşındı; (unlink oldu yeniden adlandırma bir sorun değildi) rmk1için rmk.

Bir süredir modern bir sistemde hatayı görmedim ... ama çoğu zaman kendi kendini yeniden inşa eden programlara sahip değilim.


3
İşte süper hızlı reproducer var: 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. Yeni Fedora'mda "cp: normal dosya 'a.out' yaratılamıyor: Metin dosyası meşgul" hata mesajını oluşturdu.
ArjunShankar

3
Elbette bu cevap doğrudur ve +1 alır. "Bir süredir" sorumluluk reddini kaldırmak isteyebilirsiniz.
ArjunShankar

@ArjunShankar, modern bir Linux üzerinde "doğrudan" sistem çağrıları olan bir C kopyasıdır: stackoverflow.com/questions/16764946/… GCC, bugünlerde çalışan çalıştırılabilir dosyaların üzerine yazabilir, çünkü eğer ilk önce unlinkvarsayılan olarak yapıyorsa .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

14

Bu, çekirdek tarafından o anda yürütülmekte olan bir dosyaya yazmaya çalıştığınızda veya o anda yazmak için açık olan bir dosyayı çalıştırdığınızda oluşur.

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


6

Minimum çalıştırılabilir C POSIX çoğaltma örneği

Neler olduğunu daha iyi görmek için temel API'yi anlamanızı öneririm.

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);
}

Derleyin ve çalıştırın:

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

busy.outsavları ve perrorçıktıları geçer :

Text file busy

bu yüzden mesajın glibc içinde kodlanmış olduğu sonucuna vardık.

Alternatif:

echo asdf > sleep.out

Bash çıktısını yapar:

-bash: sleep.out: Text file busy

Daha karmaşık bir uygulama için, bunu şu şekilde de gözlemleyebilirsiniz strace:

strace ./busy.out

içerenler:

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

Ubuntu 18.04, Linux kernel 4.15.0'da test edilmiştir.

Hata eğer olmaz unlinkilk

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);
}

Sonra yukarıdakilere benzer şekilde derleyin ve çalıştırın ve bu iddialar geçer.

Bu, neden bazı programlar için işe yaradığını ama diğerleri için çalışmadığını açıklar. Örneğin, yaparsanız:

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

ikinci gccçağrı adresine yazsa bile bu bir hata oluşturmaz sleep.out.

Hızlı bir şekilde straceGCC'nin yazmadan önce bağlantıyı kaldırdığını gösterir:

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

içerir:

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

Başarısız olmamasının nedeni unlink, dosyayı yeniden yazdığınızda yeni bir inode oluşturması ve çalışan yürütülebilir dosya için geçici bir sarkan inode tutmasıdır.

Ama eğer writeolmadan unlink, o zaman çalışan yürütülebilir aynı korumalı inode'a yazmaya çalışır.

POSIX 7 open()

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

[ETXTBSY]

Dosya, yürütülmekte olan saf bir prosedür (paylaşılan metin) dosyasıdır ve çoğu zaman O_WRONLY veya O_RDWR'dir.

adam 2 açık

ETXTBSY

yol adı, şu anda yürütülmekte olan ve yazma erişimi talep edilen çalıştırılabilir bir görüntüyü ifade eder.


1
Bağlantının kaldırılması durumunun mantığı, dosyaya artık bu dizinden erişilemiyor olması, ancak inode'un hala bir refcount> 0 ile orada olmasıdır. Eğer adı yeniden kullanırsanız, bu yeni bir inode'da yeni bir dosyadır - oysa önce bağlantıyı kesmezseniz, aslında korumalı inode'a yazmaya çalışıyorsunuz.
Penz

@Penz obrigado yorum için Leandro. Ayrıca, onsuz yazmaya çalışırsanız, tersine neden bir hata verdiğini de merak ediyorum unlink. Linux, ilk execaramadan sonra dosyayı bir kereden fazla okur mu?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

ETXTBSY'yi oluşturan şey, inode korumasıdır. Bağlantıyı kaldırmadan, herhangi bir yazma işlemi dosya yürütme tarafından korunan inode'a gider; bağlantı kesildiğinde, korumasız yeni bir inode alırsınız. (buradaki terimin "korumalı" olduğundan emin değilim, ama fikir bu)
Penz

5

Benim durumumda, bir csh ortamında bir kabuk dosyası (.sh uzantılı) çalıştırmaya çalışıyordum ve bu hata mesajını alıyordum.

sadece bash ile çalışıyor, benim için çalıştı. Örneğin

bash dosyası.sh


1
#!/bin/bashBaşlığı var mıydı ?
Penz

Şu başlığa sahip #! / Bin / sh
Rafayel Paremuzyan

#!/usr/bin/cshVeya eşdeğerini kullanmayı denemek isteyebilirsiniz .
Penz

3

phpredisBir Linux kutusu üzerinde derleme yapmaya sleepçalışıyorsanız, dosyayı çalıştırmadan önce bir komutla dosya izinlerini değiştirmeyi tamamlaması için ona zaman vermeniz gerekebilir :

chmod a+x /usr/bin/php/scripts/phpize \
  && sleep 1 \
  && /usr/bin/php/scripts/phpize

chmodİzinler ayarlanmadan geri döneceğini sanmıyorum . Bu bir dosya sistemi sorunu olabilir.
Penz

Bu, oluşturulmakta olan bir Docker görüntüsünün içinde meydana geldi.
Stephane

1
Docker'ın birden fazla depolama sürücüsü var, sanırım hepsi mükemmel değil.
Penz

Yine de, docker görüntüsü oluştururken bu sorunu yaşayan kişiler için çok iyi bir ipucu.
Maciej Gol

2

Nedeni bilmiyorum ama hızlı ve kolay bir çalışma ile katkıda bulunabilirim.

Bu tuhaflığı CentOS 6'da "cat> shScript.sh" (yapıştırma, ^ Z) sonrasında ve ardından dosyayı KWrite'de düzenledikten sonra yaşadım. İşin garibi, çalıştırılan betiğin fark edilebilir bir örneği (ps -ef) yoktu.

Hızlı çalışmam sadece "cp shScript.sh shScript2.sh" oldu ve ardından shScript2.sh'yi çalıştırabildim. Sonra ikisini de sildim. Bitti!


Eğer çünkü sorun oldu asmacat işlemi. Bir dahaki sefere ^ Z değil, ^ D kullanın.
Vladimir Panteleev

Oldukça doğru Vladimir. Teşekkürler! DOS / CMD komut isteminde bunu yapardım. Eski alışkanlıklar ... o zamandan beri olmadı :)
ScottWelker

2

Bunun CIFS / SMB ağ paylaşımlarında daha yaygın olduğunu görebilirsiniz. Windows, başka bir şey açık olduğunda bir dosyanın yazılmasına izin vermez ve hizmet Windows olmasa bile (başka bir NAS ürünü olabilir), muhtemelen aynı davranışı yeniden oluşturacaktır. Potansiyel olarak, kilitlenme / çoğaltma ile belirsiz bir şekilde ilgili bazı temel NAS sorununun bir göstergesi de olabilir.


2

.Sh dosyasını MobaXTerm gibi bir araçla ssh bağlantısından çalıştırıyorsanız ve söz konusu aracın yerel makineden uzak dosyayı düzenlemek için bir otomatik kaydetme yardımcı programı varsa, bu, dosyayı kilitleyecektir.

SSH oturumunu kapatmak ve yeniden açmak sorunu çözer.


1

Deneyimlerimden biri:

Her zaman tersine mühendislik yoluyla Chrome'un varsayılan klavye kısayolunu değiştiririm. Değişiklikten sonra Chrome'u kapatmayı unuttum ve aşağıdakileri çalıştırdım:

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

Strace kullanarak daha fazla ayrıntı bulabilirsiniz:

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)

0

PHP'de fopen()bir dosya üzerinde kullanırken ve daha sonra unlink()onu kullanmadan önce onu denerken karşılaştım fclose().

İyi değil:

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

İyi:

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

Pencerelerde sanırım? Linux'ta sistem genellikle açık dosyaları silmemize izin verir - dizindeki referans kaldırılır, ancak veriler (inode) yalnızca referans sayısı 0'a ulaştığında fred edilir.
Penz

Hayır, bu Centos'taydı.
dtbarne

Linux 4.7.10 üzerinde ext4 dosya sistemi ile test etti ve herhangi bir hata üretmedi, Penz'in bahsettiği gibi çalıştı. Dosya başarıyla silindi. Belki dtbarne bazı özel dosya sistemleri kullanıyor.
k3a

Bunu serseri üzerinde çalıştırıyordu - paylaşılan bir klasör olmasından kaynaklanıyor olabilir.
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

Lütfen yanıt olarak yalnızca kod göndermeyin, aynı zamanda kodunuzun ne yaptığını ve sorunun sorununu nasıl çözdüğünü de açıklayın. Açıklamalı yanıtlar genellikle daha yararlıdır ve daha kalitelidir ve olumlu oylar alma olasılığı daha yüksektir.
Mark Rotteveel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.