Was erzeugt die Meldung "Textdatei beschäftigt" in Unix?

136

Welche Operation erzeugt den Fehler "Textdatei beschäftigt"? Ich kann es nicht genau sagen.

Ich denke, es hängt damit zusammen, dass ich ein temporäres Python-Skript (mit tempfile) erstelle und daraus execl verwende, aber ich denke, dass execl die ausgeführte Datei ändert.

Penz
quelle

Antworten:

130

Dieser Fehler bedeutet, dass ein anderer Prozess oder Benutzer auf Ihre Datei zugreift. Verwenden Sie lsofdiese Option , um zu überprüfen, welche anderen Prozesse es verwenden. Sie können den killBefehl verwenden, um ihn bei Bedarf zu beenden.

jaypal singh
quelle
115
Bei dem Text file busyFehler handelt es sich insbesondere um den Versuch, eine ausführbare Datei während der Ausführung zu ändern. Der "Text" bezieht sich hier auf die Tatsache, dass die zu ändernde Datei das Textsegment für ein laufendes Programm ist. Dies ist ein ganz besonderer Fall und nicht der generische, den Ihre Antwort zu suggerieren scheint. Trotzdem ist Ihre Antwort nicht ganz falsch.
ArjunShankar
4
Die Antwort mit dem Kommentar scheint vollständig zu sein.
Penz
Das OP fragte, welche Operation den Fehler erzeugt, und nicht, um zu erklären, was der Fehler bedeutet.
WonderWorker
Ich denke, die Tatsache, dass Unix davon ausgeht, dass Dateien "Textdateien" sind, ist unlogisch. In meinem Fall war es eine Binärdatei, die diesen Fehler ausgelöst hat.
Felipe Valdes
1
@FelipeValdes Der Name ist historisch aus der Terminologie von vor einem halben Jahrhundert. Beispielsweise unterschied sich in Multics das Textsegment eines Programms vom Verknüpfungssegment, und noch frühere Leute sprachen über Binärtext. stackoverflow.com/a/1282540/833300
jma
30

Es ist schon eine Weile her, dass ich diese Nachricht gesehen habe, aber sie war vor gut ein paar Jahrzehnten in System V R3 oder so weit verbreitet. Damals bedeutete dies, dass Sie eine ausführbare Programmdatei während der Ausführung nicht ändern konnten.

Zum Beispiel baute ich ein makeWorkalike namens rmk, und nach einer Weile war es selbsterhaltend. Ich würde die Entwicklungsversion ausführen und eine neue Version erstellen lassen. Um es zum Laufen zu bringen, musste die Problemumgehung verwendet werden:

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

Um Probleme mit der 'Textdatei beschäftigt' zu vermeiden, erstellte der Build eine neue Datei rmk1, verschob dann die alte rmkin rmk2(Umbenennen war kein Problem; Verknüpfung aufheben war) und verschob die neu erstellte rmk1in rmk.

Ich habe den Fehler auf einem modernen System schon eine ganze Weile nicht mehr gesehen ... aber ich habe nicht allzu oft Programme, die sich selbst neu erstellen.

Jonathan Leffler
quelle
3
Hier ist ein superschneller Wiedergabegerät : 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. Auf meinem neuen Fedora wurde die Fehlermeldung "cp: Es kann keine reguläre Datei 'a.out': Textdatei beschäftigt" erstellt.
ArjunShankar
3
Natürlich ist diese Antwort richtig und erhält +1. Möglicherweise möchten Sie den Haftungsausschluss "Es ist eine Weile her" entfernen.
ArjunShankar
@ArjunShankar hier ist eine C-Reproduktion unter einem modernen Linux mit "direkten" Systemaufrufen: stackoverflow.com/questions/16764946/… GCC kann heutzutage nur laufende ausführbare Dateien überschreiben, da dies unlinkstandardmäßig zuerst geschieht .
Ciro Santilli 法轮功 冠状 病 六四 事件 21
14

Dies tritt auf, wenn Sie versuchen, in eine Datei zu schreiben, die gerade vom Kernel ausgeführt wird, oder wenn Sie eine Datei ausführen, die derzeit zum Schreiben geöffnet ist.

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

Messa
quelle
6

Beispiel für eine minimal ausführbare C POSIX-Reproduktion

Ich empfehle, die zugrunde liegende API zu verstehen, um besser sehen zu können, was los ist.

sleep.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

beschäftigt.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);
}

Kompilieren und ausführen:

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

busy.outÜbergibt die Asserts und perrorgibt Folgendes aus:

Text file busy

Daraus schließen wir, dass die Nachricht in glibc selbst fest codiert ist.

Alternative:

echo asdf > sleep.out

macht Bash-Ausgabe:

-bash: sleep.out: Text file busy

Für eine komplexere Anwendung können Sie sie auch beobachten mit strace:

strace ./busy.out

was beinhaltet:

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

Getestet unter Ubuntu 18.04, Linux Kernel 4.15.0.

Der Fehler tritt nicht auf, wenn Sie unlinkzuerst

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

Dann kompilieren und analog zu den oben genannten ausführen, und diese Behauptungen bestehen.

Dies erklärt, warum es für bestimmte Programme funktioniert, für andere jedoch nicht. ZB wenn Sie tun:

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

Das erzeugt keinen Fehler, obwohl der zweite gccAufruf an schreibt sleep.out.

Eine stracekurze Darstellung zeigt, dass GCC vor dem Schreiben zuerst die Verknüpfung aufhebt:

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

enthält:

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

Der Grund, warum dies nicht fehlschlägt, besteht darin, dass beim unlinkerneuten Schreiben der Datei ein neuer Inode erstellt wird und ein temporärer baumelnder Inode für die ausgeführte ausführbare Datei beibehalten wird.

Wenn Sie jedoch nur writeohne sind unlink, wird versucht, in denselben geschützten Inode wie die laufende ausführbare Datei zu schreiben.

POSIX 7 open()

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

[ETXTBSY]

Die Datei ist eine reine Prozedurdatei (gemeinsam genutzter Text), die ausgeführt wird, und oflag ist O_WRONLY oder O_RDWR.

Mann 2 offen

ETXTBSY

Pfadname bezieht sich auf ein ausführbares Image, das gerade ausgeführt wird und Schreibzugriff angefordert wurde.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
1
Der Grund für den Unlink-Fall ist, dass auf die Datei von diesem Verzeichnis aus nicht mehr zugegriffen werden kann, der Inode jedoch weiterhin mit einem Refcount> 0 vorhanden ist. Wenn Sie den Namen erneut verwenden, handelt es sich um eine neue Datei in einem neuen Inode - während if Wenn Sie nicht zuerst die Verknüpfung aufheben, versuchen Sie tatsächlich, in den geschützten Inode zu schreiben.
Penz
@ Penz obrigado für den Kommentar, Leandro. Ich frage mich auch, warum es umgekehrt einen Fehler gibt, wenn Sie versuchen, ohne zu schreiben unlink. Liest Linux die Datei nach dem ersten execAufruf mehr als einmal ?
Ciro Santilli 法轮功 冠状 病 六四 事件 22
Was den ETXTBSY generiert, ist der Inode-Schutz. Ohne Verknüpfung zu entfernen, werden alle Schreibvorgänge an den Inode gesendet, der durch die Dateiausführung geschützt ist. Mit Unlink erhalten Sie einen neuen Inode, der nicht geschützt ist. (nicht sicher, ob "geschützt" der Begriff hier ist, aber das ist die Idee)
Penz
5

In meinem Fall habe ich versucht, eine Shell-Datei (mit der Erweiterung .sh) in einer csh-Umgebung auszuführen, und diese Fehlermeldung wurde angezeigt.

Nur mit Bash zu laufen, hat bei mir funktioniert. Beispielsweise

bash file.sh

Rafayel Paremuzyan
quelle
1
Hatte es einen #!/bin/bashHeader?
Penz
Es hat den folgenden Header #! / Bin / sh
Rafayel Paremuzyan
Vielleicht möchten Sie es mit #!/usr/bin/cshoder gleichwertig versuchen .
Penz
3

Wenn Sie versuchen, phpredisauf einer Linux-Box aufzubauen, müssen Sie ihr möglicherweise Zeit geben, um die Dateiberechtigungen mit einem sleepBefehl zu ändern, bevor Sie die Datei ausführen:

chmod a+x /usr/bin/php/scripts/phpize \
  && sleep 1 \
  && /usr/bin/php/scripts/phpize
Stephane
quelle
Ich glaube nicht, dass ich zurückkehren chmodwürde, bevor die Berechtigungen festgelegt wurden. Dies könnte ein Problem mit dem Dateisystem sein.
Penz
Dies geschah in einem Docker-Image, das gerade erstellt wurde.
Stephane
1
Docker hat mehrere Speichertreiber, ich denke nicht alle sind perfekt.
Penz
Dennoch ist es ein sehr guter Hinweis für Personen, bei denen dieses Problem beim Erstellen eines Docker-Images auftritt.
Maciej Gol
2

Ich kenne die Ursache nicht, aber ich kann schnell und einfach Abhilfe schaffen.

Ich habe diese Seltsamkeit unter CentOS 6 gerade erlebt, nachdem "cat> shScript.sh" (Einfügen, ^ Z) und dann die Datei in KWrite bearbeitet wurden. Seltsamerweise war keine Instanz (ps -ef) des ausgeführten Skripts erkennbar.

Meine schnelle Lösung bestand einfach darin, "cp shScript.sh shScript2.sh" zu verwenden, dann konnte ich shScript2.sh ausführen. Dann habe ich beide gelöscht. Getan!

ScottWelker
quelle
Ihr Problem war, dass Sie den Prozess ausgesetztcat haben. Verwenden Sie das nächste Mal ^ D, nicht ^ Z.
Vladimir Panteleev
Ganz richtig Vladimir. Vielen Dank! Das hätte ich in der DOS / CMD-Eingabeaufforderung getan. Alte Gewohnheiten ... ist seitdem nicht mehr passiert :)
ScottWelker
2

Möglicherweise ist dies bei CIFS / SMB-Netzwerkfreigaben häufiger der Fall. Windows erlaubt nicht, dass eine Datei geschrieben wird, wenn diese Datei in einer anderen Datei geöffnet ist, und selbst wenn der Dienst nicht Windows ist (es kann sich um ein anderes NAS-Produkt handeln), wird wahrscheinlich dasselbe Verhalten reproduziert. Möglicherweise ist dies auch eine Manifestation eines zugrunde liegenden NAS-Problems, das vage mit dem Sperren / Replizieren zusammenhängt.

Cameron Kerr
quelle
2

Wenn Sie die .sh-Datei über eine SSH-Verbindung mit einem Tool wie MobaXTerm ausführen und dieses Tool über ein Dienstprogramm zum automatischen Speichern zum Bearbeiten der Remote-Datei vom lokalen Computer verfügt, wird die Datei gesperrt.

Das Schließen und erneute Öffnen der SSH-Sitzung löst das Problem.

Poutrathor
quelle
1

Eine meiner Erfahrungen:

Ich ändere immer die Standardtastenkürzel von Chrome durch Reverse Engineering. Nach der Änderung habe ich vergessen, Chrome zu schließen, und Folgendes ausgeführt:

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

Mit strace finden Sie weitere Details:

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

Ich bin in PHP darauf gestoßen, als ich fopen()eine Datei verwendet habe und es dann versucht habe, unlink()bevor ich sie verwendet fclose()habe.

Nicht gut:

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

Gut:

$handle = fopen('file.txt');
// do something
fclose($handle);
unlink('file.txt');
dtbarne
quelle
Unter Windows, denke ich? Unter Linux erlaubt uns das System normalerweise, geöffnete Dateien zu löschen - die Referenz im Verzeichnis wird entfernt, aber die Daten (Inode) werden nur dann gelöscht, wenn die Anzahl der Referenzen 0 erreicht.
Penz
Nein, das war auf Centos.
dtbarne
Getestet unter Linux 4.7.10 mit ext4-Dateisystem und es hat keinen Fehler erzeugt, funktionierte wie Penz erwähnt. Datei erfolgreich gelöscht. Vielleicht verwendet dtbarne ein spezielles Dateisystem.
k3a
Wurde dies auf Vagrant ausgeführt - könnte daran liegen, dass es sich um einen freigegebenen Ordner handelt.
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
quelle
Bitte posten Sie nicht nur Code als Antwort, sondern geben Sie auch eine Erklärung, was Ihr Code tut und wie er das Problem der Frage löst. Antworten mit einer Erklärung sind in der Regel hilfreicher und von besserer Qualität und ziehen eher positive Stimmen an.
Mark Rotteveel