在UNIX中,什么会生成“文本文件忙”消息?

什么操作生成错误“文本文件忙”?我不能确切地说。

我认为这与我正在创建一个临时Python脚本(使用tempfile)并从中使用execl有关,但我认为execl会更改正在运行的文件。

285522 次浏览

此错误意味着您正试图在可执行文件执行时对其进行修改。“文本”这里指的是被修改的文件是正在运行的程序的文本段。使用lsof来检查哪些其他进程正在使用它。如果需要,您可以使用kill命令来终止它。

我已经有一段时间没有看到这条消息了,但在几十年前,它曾经在系统V R3或其附近流行。当时,这意味着您不能在程序运行时更改其可执行文件。

例如,我构建了一个类似于makermk,过了一段时间,它就可以自我维护了。我会运行开发版本,并让它构建一个新版本。要使其正常工作,必须使用解决方法:

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

因此,为了避免“文本文件忙”的问题,构建创建了一个新的文件rmk1,然后将旧的rmk移动到rmk2(重命名不是问题;Unlink was),然后将新建的rmk1移动到rmk

我已经很久没有在现代系统上看到这个错误了……但我并不经常让程序自我重建。

我不知道原因,但我可以提供一个快速简单的解决方案。

cat > shScript.sh(粘贴,^Z),然后在KWrite中编辑文件之后,我刚刚在CentOS 6上经历了这种奇怪的事情。奇怪的是,没有可识别的脚本执行实例(ps -ef)。

我的快速工作是简单地cp shScript.sh shScript2.sh,然后我能够执行shScript2.sh。然后我两个都删了。完成!

我在PHP中遇到过这种情况,当时我在一个文件上使用fopen(),然后在对其使用fclose()之前,尝试unlink()

不好:

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

良好:

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

您可能会发现这种情况在CIFS/SMB网络共享上更为常见。Windows不允许在其他程序打开文件时写入该文件,即使该服务不是Windows(可能是其他NAS产品),它也可能会复制相同的行为。这也可能是一些与锁定/复制模糊相关的底层NAS问题的表现。

我的经验之一:

我总是通过逆向工程来更改Chrome的默认键盘快捷键。修改后,我忘记关闭Chrome,运行了以下内容:

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

使用strace,您可以找到更多详细信息:

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

如果尝试在Linux机器上构建phpredis,您可能需要在运行该文件之前,使用sleep命令给它一些时间来完成修改文件权限:

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

在我的例子中,我尝试执行一个shell文件(扩展名为.sh)。 在CSH环境中,我收到了错误消息。

只是和巴什一起跑步,对我来说很有效。 比如说

Bash文件.sh

最小可运行C POSIX复制示例

我建议您了解底层API,以便更好地了解正在发生的事情。

睡眠C

#define _XOPEN_SOURCE 700
#include <unistd.h>


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

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

编译并运行:

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

busy.out传递断言,perror输出:

Text file busy

因此,我们推断消息是在glibc本身中硬编码的。

或者:

echo asdf > sleep.out

生成bash输出:

-bash: sleep.out: Text file busy

对于更复杂的应用程序,您还可以使用strace

strace ./busy.out

其中包含:

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

在Ubuntu 18.04和Linux内核4.15.0上进行了测试。

如果先unlink,则不会发生此错误

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

然后以类似于上面的方式编译和运行,这些断言通过。

这就解释了为什么它只适用于某些程序,而不适用于其他程序。例如,如果您这样做:

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

即使第二个gcc调用正在写入sleep.out,也不会生成错误。

快速strace显示,GCC在写入之前首先取消链接:

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

包含:

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

它没有失败的原因是,当您unlink并重写该文件时,它会创建一个新的索引节点,并为正在运行的可执行文件保留一个临时悬空索引节点。

但是,如果您只write,而不unlink,则它会尝试写入与正在运行的可执行文件相同的受保护inode.

POSIX 7open()

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

[ETXTBSY]

该文件是正在执行的纯过程(共享文本)文件,并且oflag是o_wronly或o_rdwr.

男子2号开门

Etxtbsy

路径名是指当前正在执行并请求写入访问的可执行映像。

Glibc源

2.30上的快速grep给出:

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

以及在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

如果您使用类似MobaxTerm的工具从SSH连接运行.sh,并且如果所述工具具有用于从本地计算机编辑远程文件的自动保存实用程序,则将锁定该文件。

关闭并重新打开SSH会话可以解决这个问题。

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

当执行的脚本文件使用#!/usr/bin/env shebang行,而忽略实际环境(例如bash)时,也会发生这种情况。