Ejemplo de reproducción mínima C POSIX ejecutable
Recomiendo comprender la API subyacente para ver mejor lo que está sucediendo.
dormir.c
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
sleep(10000);
}
ocupado.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);
}
Compilar y ejecutar:
gcc -std=c99 -o sleep.out ./sleep.c
gcc -std=c99 -o busy.out ./busy.c
./sleep.out &
./busy.out
busy.out
pasa las afirmaciones y perror
salidas:
Text file busy
entonces deducimos que el mensaje está codificado en glibc.
Alternativamente:
echo asdf > sleep.out
hace la salida de Bash:
-bash: sleep.out: Text file busy
Para una aplicación más compleja, también puede observarla con strace
:
strace ./busy.out
que contiene:
openat(AT_FDCWD, "sleep.out", O_WRONLY) = -1 ETXTBSY (Text file busy)
Probado en Ubuntu 18.04, kernel de Linux 4.15.0.
El error no ocurre si unlink
primero
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);
}
Luego compila y ejecuta de forma análoga a la anterior, y esas afirmaciones pasan.
Esto explica por qué funciona para ciertos programas pero no para otros. Por ejemplo, si lo haces:
gcc -std=c99 -o sleep.out ./sleep.c
./sleep.out &
gcc -std=c99 -o sleep.out ./sleep.c
eso no genera un error, aunque la segunda gcc
llamada esté escribiendo en sleep.out
.
Un rápido strace
muestra que GCC primero se desvincula antes de escribir:
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
La razón por la que no falla es que cuando unlink
y reescribe el archivo, crea un nuevo inodo y mantiene un inodo colgante temporal para el archivo ejecutable en ejecución.
Pero si solo write
sinunlink
, entonces intenta escribir en el mismo inodo protegido que el ejecutable en ejecución.
POSIX 7 open()
http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
[ETXTBSY]
El archivo es un archivo de procedimiento puro (texto compartido) que se está ejecutando y oflag es O_WRONLY u O_RDWR.
hombre 2 abierto
ETXTBSY
ruta se refiere a una imagen ejecutable que se está ejecutando actualmente y se solicitó acceso de escritura.
Text file busy
error en específico se trata de intentar modificar un ejecutable mientras se está ejecutando. El "Texto" aquí se refiere al hecho de que el archivo que se está modificando es el segmento de texto para un programa en ejecución. Este es un caso muy especial, y no el genérico que su respuesta parece sugerir. Aun así, su respuesta no es del todo incorrecta.