Cosa genera il messaggio "file di testo occupato" in Unix?


137

Quale operazione genera l'errore "file di testo occupato"? Non sono in grado di dire esattamente.

Penso che sia legato al fatto che sto creando uno script Python temporaneo (usando tempfile) e usando execl da esso, ma penso che execl cambi il file in esecuzione.

Risposte:


130

Questo errore indica che un altro processo o utente sta accedendo al tuo file. Utilizzare lsofper verificare quali altri processi lo stanno utilizzando. Puoi usare il killcomando per ucciderlo se necessario.


115
L' Text file busyerrore in particolare riguarda il tentativo di modificare un eseguibile mentre è in esecuzione. Il "Testo" qui si riferisce al fatto che il file che si sta modificando è il segmento di testo per un programma in esecuzione. Questo è un caso molto speciale, e non quello generico che la tua risposta sembra suggerire. Anche così, la tua risposta non è del tutto errata.
ArjunShankar,

4
La risposta con il commento sembra completa.
Penz,

L'OP ha chiesto quale operazione genera l'errore, non per una spiegazione del significato dell'errore.
WonderWorker,

Penso che il fatto che unix presuma che i file siano "file di testo" è ilogico, nel mio caso è stato un file binario che ha provocato questo errore.
Felipe Valdes l'

1
@FelipeValdes Il nome è storico dalla terminologia di mezzo secolo fa. Ad esempio, in multics il segmento di testo di un programma era distinto dal segmento di collegamento, e anche le persone precedenti parlavano di testo binario. stackoverflow.com/a/1282540/833300
jma

30

È da un po 'che non vedo quel messaggio, ma era prevalente in System V R3 o giù di lì un bel paio di decenni fa. Allora, significava che non era possibile modificare un eseguibile del programma mentre era in esecuzione.

Ad esempio, stavo costruendo un makeworkalike chiamato rmk, e dopo un po 'si auto-manteneva. Avrei eseguito la versione di sviluppo e l'avrei costruita una nuova versione. Per farlo funzionare, era necessario utilizzare la soluzione alternativa:

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

Quindi, per evitare problemi con il "file di testo occupato", la build ha creato un nuovo file rmk1, quindi ha spostato il vecchio rmkin rmk2(rinominare non era un problema; unlink era) e quindi spostato il nuovo costruito rmk1in rmk.

Non vedo l'errore su un sistema moderno da un po 'di tempo ... ma non ho spesso programmi che si ricostruiscono da soli.


3
Ecco un super riproduttore rapida: 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. Ha prodotto il messaggio di errore "cp: impossibile creare il file regolare 'a.out': file di testo occupato" sul mio Fedora nuovo.
Arjun Shank

3
Naturalmente, questa risposta è corretta e ottiene un +1. Potresti voler rimuovere la dichiarazione di non responsabilità "È passato un po 'di tempo".
ArjunShankar,

@ArjunShankar qui è una riproduzione C su un moderno Linux con chiamate di sistema "dirette": stackoverflow.com/questions/16764946/… GCC può sovrascrivere solo eseguibili in esecuzione al giorno d'oggi perché se prima lo fa unlinkper impostazione predefinita.
Ciro Santilli 21 冠状 病 六四 事件 法轮功

14

Ciò si verifica quando si tenta di scrivere su un file che è attualmente in esecuzione dal kernel o si esegue un file che è attualmente aperto per la scrittura.

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


6

Esempio di riproduzione POSIX C eseguibile minima

Consiglio di comprendere l'API sottostante per vedere meglio cosa sta succedendo.

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

Compila ed esegui:

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

busy.outpassa le affermazioni e perrorproduce:

Text file busy

quindi deduciamo che il messaggio è hardcoded nello stesso glibc.

In alternativa:

echo asdf > sleep.out

rende l'uscita Bash:

-bash: sleep.out: Text file busy

Per un'applicazione più complessa, puoi anche osservarla con strace:

strace ./busy.out

che contiene:

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

Testato su Ubuntu 18.04, kernel Linux 4.15.0.

L'errore non si verifica se unlinkprima

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

Quindi compilare ed eseguire in modo analogo a quanto sopra, e tali affermazioni passano.

Questo spiega perché funziona per determinati programmi ma non per altri. Ad esempio se lo fai:

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

che non genera un errore, anche se la seconda gccchiamata sta scrivendo sleep.out.

Un rapido stracemostra che GCC prima scollega prima di scrivere:

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

contiene:

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

Il motivo per cui non fallisce è che quando si unlinkriscrive il file, crea un nuovo inode e mantiene un inode temporaneo pendente per il file eseguibile in esecuzione.

Ma se proprio writesenza unlink, allora prova a scrivere sullo stesso inode protetto dell'eseguibile in esecuzione.

POSIX 7 open()

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

[ETXTBSY]

Il file è un file di procedura pura (testo condiviso) che viene eseguito e oflag è O_WRONLY o O_RDWR.

man 2 open

ETXTBSY

nome percorso si riferisce a un'immagine eseguibile che è attualmente in esecuzione ed è stato richiesto l'accesso in scrittura.


1
La logica del caso di scollegamento è che il file non è più accessibile da quella directory, ma l'inode è ancora lì con un refcount> 0. Se riutilizzi il nome, allora è un nuovo file in un nuovo inode - mentre se non scollegare prima, in realtà stai provando a scrivere sull'inode protetto.
Penz,

@Penz obrigado per il commento, Leandro. Mi chiedo anche perché, al contrario, dia un errore se si tenta di scrivere senza unlink. Linux ha mai letto il file più di una volta dopo la prima execchiamata?
Ciro Santilli 22 冠状 病 六四 事件 法轮功

Ciò che sta generando ETXTBSY è la protezione dell'inode. Senza scollegare, tutte le scritture passano all'inode protetto dall'esecuzione del file; con unlink, si ottiene un nuovo inode che non è protetto. (non sono sicuro che "termine" sia il termine qui, ma questa è l'idea)
Penz

5

Nel mio caso, stavo cercando di eseguire un file shell (con estensione .sh) in un ambiente csh e stavo ricevendo quel messaggio di errore.

solo correndo con bash ha funzionato per me. Per esempio

bash file.sh


1
Aveva #!/bin/bashun'intestazione?
Penz,

Ha la seguente intestazione #! / Bin / sh
Rafayel Paremuzyan,

Potresti provare a utilizzare #!/usr/bin/csho equivalente.
Penz,

3

Se phpredisstai tentando di compilare su un box Linux, potresti dover concedere il tempo necessario per completare la modifica delle autorizzazioni del file, con un sleepcomando, prima di eseguire il file:

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

Non credo chmodche tornerebbe prima che le autorizzazioni fossero impostate. Potrebbe essere un problema con il filesystem.
Penz,

Ciò si è verificato all'interno di un'immagine Docker in fase di creazione.
Stephane,

1
Docker ha più driver di archiviazione, suppongo che non tutti siano perfetti.
Penz,

Tuttavia, è un ottimo suggerimento per le persone che riscontrano questo problema durante la creazione dell'immagine docker.
Maciej Gol,

2

Non conosco la causa, ma posso contribuire in modo rapido e semplice.

Ho appena sperimentato questa stranezza su CentOS 6 dopo "cat> shScript.sh" (incolla, ^ Z), quindi modificando il file in KWrite. Stranamente non c'era un'istanza riconoscibile (ps -ef) dell'esecuzione dello script.

Il mio rapido lavoro era semplicemente "cp shScript.sh shScript2.sh", quindi sono stato in grado di eseguire shScript2.sh. Quindi ho eliminato entrambi. Fatto!


Il tuo problema era perché hai sospeso il catprocesso. La prossima volta usa ^ D, non ^ Z.
Vladimir Panteleev,

Proprio vero Vladimir. Grazie! Questo è quello che avrei fatto nel prompt di DOS / CMD. Vecchi habbit ... non è più successo da :)
ScottWelker,

2

È possibile che questo sia più comune nelle condivisioni di rete CIFS / SMB. Windows non consente la scrittura di un file quando qualcos'altro ha quel file aperto e anche se il servizio non è Windows (potrebbe essere un altro prodotto NAS), probabilmente riprodurrà lo stesso comportamento. Potenzialmente, potrebbe anche essere una manifestazione di alcuni problemi NAS sottostanti vagamente correlati al blocco / replica.


2

Se stai eseguendo il .sh da una connessione ssh con uno strumento come MobaXTerm, e se detto strumento ha un'utilità di salvataggio automatico per modificare il file remoto dal computer locale, questo bloccherà il file.

La chiusura e la riapertura della sessione SSH la risolvono.


1

Una mia esperienza:

Cambio sempre la scorciatoia da tastiera predefinita di Chrome tramite il reverse engineering. Dopo la modifica, ho dimenticato di chiudere Chrome ed ho eseguito quanto segue:

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

Usando strace, puoi trovare maggiori dettagli:

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

Mi sono imbattuto in PHP quando ho usato fopen()un file e poi ci unlink()ho provato prima di usarlo fclose().

Non buono:

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

Buona:

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

Su Windows immagino? Su Linux il sistema di solito ci consente di eliminare i file aperti - il riferimento nella directory viene eliminato, ma i dati (inode) sono fred solo quando il numero di riferimenti raggiunge 0.
Penz

No, questo era su Centos.
dtbarne,

Provato su Linux 4.7.10 con filesystem ext4 e non ha prodotto alcun errore, ha funzionato come menzionato da Penz. File eliminato correttamente. Forse dtbarne sta usando un filesystem speciale.
k3a,

Lo stava eseguendo su Vagrant - potrebbe essere dovuto al fatto che era una cartella condivisa.
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

Si prega di non pubblicare solo il codice come risposta, ma anche di fornire una spiegazione su cosa fa il codice e su come risolve il problema della domanda. Le risposte con una spiegazione sono generalmente più utili e di migliore qualità e hanno maggiori probabilità di attirare voti positivi.
Mark Rotteveel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.