192 votes

Qu'est-ce qui génère le message "fichier texte occupé" sous Unix ?

Quelle opération génère l'erreur "fichier texte occupé" ? Je suis incapable de le dire exactement.

Je pense que c'est lié au fait que je crée un script python temporaire (en utilisant tempfile) et que j'utilise execl à partir de celui-ci, mais je pense que execl modifie le fichier en cours d'exécution.

204voto

jaypal Points 34440

Cette erreur signifie que vous essayez de modifier un exécutable pendant qu'il s'exécute. Le "Texte" fait ici référence au fait que le fichier en cours de modification est le segment de texte d'un programme en cours d'exécution. Utilisez lsof pour vérifier quels autres processus l'utilisent. Vous pouvez utiliser kill pour le tuer si nécessaire.

33voto

Jonathan Leffler Points 299946

Cela fait longtemps que je n'ai pas vu ce message, mais il était répandu dans le Système V R3 ou dans les environs il y a une bonne vingtaine d'années. A l'époque, cela signifiait que vous ne pouviez pas modifier l'exécutable d'un programme en cours d'exécution.

Par exemple, je construisais un make qui s'appelle rmk et après un certain temps, il s'est auto-entretenu. J'exécutais la version de développement et je lui faisais construire une nouvelle version. Pour la faire fonctionner, il était nécessaire d'utiliser la solution de contournement :

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

Ainsi, afin d'éviter les problèmes liés au "fichier texte occupé", le build a créé un nouveau fichier rmk1 puis a déplacé l'ancien rmk à rmk2 (renommer n'était pas un problème, mais délier l'était), et ensuite déplacer le nouveau fichier rmk1 à rmk .

Je n'ai pas vu cette erreur sur un système moderne depuis un certain temps... mais je n'ai pas si souvent des programmes qui se reconstruisent eux-mêmes.

28voto

Messa Points 5988

Cela se produit lorsque vous essayez d'écrire dans un fichier qui est en cours d'exécution par le noyau, ou d'exécuter un fichier qui est actuellement ouvert à l'écriture.

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

15voto

Ciro Santilli Points 3341

Exemple de reproduction POSIX minimale exécutable en C

Je recommande de comprendre l'API sous-jacente pour mieux comprendre ce qui se passe.

sleep.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

occupé.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);
}

Compilez et exécutez :

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

busy.out passe les assertions, et perror sorties :

Text file busy

Nous en déduisons donc que le message est codé en dur dans la glibc elle-même.

Alternativement :

echo asdf > sleep.out

fait une sortie Bash :

-bash: sleep.out: Text file busy

Pour une application plus complexe, vous pouvez également l'observer avec strace :

strace ./busy.out

qui contient :

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

Testé sur Ubuntu 18.04, noyau Linux 4.15.0.

L'erreur ne se produit pas si vous unlink premièrement

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

Puis compilez et exécutez de manière analogue à ce qui précède, et ces assertions passent.

Cela explique pourquoi cela fonctionne pour certains programmes mais pas pour d'autres. Par exemple, si vous le faites :

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

qui ne génère pas d'erreur, même si la seconde gcc L'appel écrit à sleep.out .

Un rapide strace montre que GCC commence par délier les liens avant d'écrire :

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

contient :

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

La raison pour laquelle il n'échoue pas est que lorsque vous unlink et réécrire le fichier, il crée un nouvel inode, et garde un inode temporaire pour le fichier exécutable en cours d'exécution.

Mais si tu veux juste write sans unlink puis il essaie d'écrire sur le même inode protégé que l'exécutable en cours d'exécution.

POSIX 7 open()

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

[ETXTBSY]

Le fichier est un fichier de procédure pure (texte partagé) qui est en cours d'exécution et oflag est O_WRONLY ou O_RDWR.

homme 2 ouvert

ETXTBSY

Le nom du chemin fait référence à une image exécutable qui est en cours d'exécution et pour laquelle un accès en écriture a été demandé.

source glibc

Un rapide grep sur 2.30 donne :

sysdeps/gnu/errlist.c:299:    [ERR_REMAP (ETXTBSY)] = N_("Text file busy"),
sysdeps/mach/hurd/bits/errno.h:62:  ETXTBSY                        = 0x4000001a,        /* Text file busy */

et une frappe manuelle dans manual/errno.texi :

@deftypevr Macro int ETXTBSY
@standards{BSD, errno.h}
@errno{ETXTBSY, 26, Text file busy}
An attempt to execute a file that is currently open for writing, or
write to a file that is currently being executed.  Often using a
debugger to run a program is considered having it open for writing and
will cause this error.  (The name stands for ``text file busy''.)  This
is not an error on @gnuhurdsystems{}; the text is copied as necessary.
@end deftypevr

7voto

Dans mon cas, j'essayais d'exécuter un fichier shell (avec une extension .sh) dans un environnement csh, et j'ai obtenu ce message d'erreur.

juste en exécutant avec bash ça a marché pour moi. Par exemple

bash file.sh

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X