web-dev-qa-db-fra.com

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 dire exactement.

Je pense que cela est lié au fait que je crée un script python temporaire (en utilisant tempfile) et en utilisant execl, mais je pense que execl modifie le fichier en cours d'exécution.

102
Penz

Cette erreur signifie qu'un autre processus ou utilisateur accède à votre fichier. Utilisez lsof pour vérifier quels autres processus l'utilisent. Vous pouvez utiliser la commande kill pour le tuer si nécessaire.

87
jaypal singh

Cela fait longtemps que je n'ai pas vu ce message, mais il prévalait dans le système V R3 ou il y a une vingtaine d'années. À l'époque, cela signifiait que vous ne pouviez pas modifier un exécutable de programme pendant son exécution.

Par exemple, je construisais un make workalike appelé rmk et après un certain temps, il s'est auto-entretenu. Je voudrais exécuter la version de développement et le faire construire une nouvelle version. Pour que cela fonctionne, 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, pour éviter les problèmes avec le «fichier texte occupé», la construction a créé un nouveau fichier rmk1, puis a déplacé l'ancien rmk à rmk2 (renommer ne posait pas de problème; unlink était), puis a déplacé le rmk1 nouvellement créé à rmk.

Je n'ai pas vu l'erreur sur un système moderne depuis un bon moment ... mais je n'ai pas souvent des programmes qui se reconstruisent.

28
Jonathan Leffler

Cela se produit lorsque vous essayez d'écrire dans un fichier en cours d'exécution par le noyau ou d'exécuter un fichier en cours d'écriture.

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

9
Messa

Dans mon cas, j’essayais d’exécuter un fichier Shell (avec une extension .sh) Dans un environnement csh et j’obtenais ce message d’erreur.

juste courir avec bash cela a fonctionné pour moi . Par exemple

bash fichier.sh

3

Vous constaterez peut-être que cela est plus courant sur les partages réseau CIFS/SMB. Windows n'autorise pas l'écriture d'un fichier lorsque quelque chose d'autre l'ouvre, et même si le service n'est pas Windows (il peut s'agir d'un autre produit NAS), il reproduira probablement le même comportement. Potentiellement, il pourrait également s'agir d'une manifestation d'un problème sous-jacent NAS lié vaguement au verrouillage/à la réplication.

2
Cameron Kerr

Si vous essayez de construire phpredis sur une machine Linux, vous devrez peut-être lui donner le temps de modifier les autorisations de fichiers à l'aide d'une commande sleep avant d'exécuter le fichier:

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

Je ne connais pas la cause, mais je peux contribuer rapidement et facilement au travail.

Je viens de faire l'expérience de cette bizarrerie sur CentOS 6 après "cat> shScript.sh" (coller, ^ Z), puis l'édition du fichier dans KWrite. Curieusement, il n'y avait pas d'instance discernable (ps -ef) du script en cours d'exécution.

Mon travail rapide consistait simplement à "cp shScript.sh shScript2.sh", puis j'ai pu exécuter shScript2.sh. Puis j'ai supprimé les deux. Terminé!

2
ScottWelker

Une de mes expériences:

Je change toujours le raccourci clavier par défaut de Chrome via le reverse engineering. Après modification, j'ai oublié de fermer Chrome et j'ai exécuté ce qui suit:

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

En utilisant strace, vous pouvez trouver plus de détails:

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)
1
firo

Minimal exécutable C Exemple de reproduction POSIX

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

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

Compiler et exécuter:

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 génère:

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

rend la sortie de 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 premier

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

Ensuite, 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 tu fais:

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

cela ne génère pas d'erreur, même si le deuxième appel gcc écrit dans sleep.out.

Une rapide strace montre que GCC dissocie d'abord 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 cela n'échoue pas, c'est que lorsque vous unlink et ré-écrivez le fichier, il crée un nouvel inode et conserve un inode temporaire pour le fichier exécutable en cours d'exécution.

Mais si vous ne faites que write sans unlink, il essaiera 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é) en cours d'exécution et oflag est O_WRONLY ou O_RDWR.

man 2 ouvert

ETXTBSY

pathname fait référence à une image exécutable en cours d'exécution et un accès en écriture a été demandé.

Si vous exécutez le fichier .sh à partir d'une connexion ssh avec un outil tel que MobaXTerm et que cet outil dispose d'un utilitaire d'enregistrement automatique permettant de modifier un fichier distant à partir d'une machine locale, le fichier sera verrouillé.

Fermer et rouvrir la session SSH le résout.

0
Poutrathor

Je suis tombé sur cette information dans PHP en utilisant fopen() sur un fichier, puis en essayant de le unlink() avant d'utiliser fclose() dessus.

Pas bien:

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

Bien:

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