What generates the “text file busy” message in Unix?

前端 未结 12 1948
渐次进展
渐次进展 2020-12-04 06:38

What operation generates the error \"text file busy\"? I am unable to tell exactly.

I think it is related to the fact that I\'m creating a temporary python script (u

相关标签:
12条回答
  • 2020-12-04 07:07

    If you are running the .sh from a ssh connection with a tool like MobaXTerm, and if said tool has an autosave utility to edit remote file from local machine, that will lock the file.

    Closing and reopening the SSH session solves it.

    0 讨论(0)
  • 2020-12-04 07:09

    This error means some other process or user is accessing your file. Use lsof to check what other processes are using it. You can use kill command to kill it if needed.

    0 讨论(0)
  • 2020-12-04 07:09

    You may find this to be more common on CIFS/SMB network shares. Windows doesn't allow for a file to be written when something else has that file open, and even if the service is not Windows (it might be some other NAS product), it will likely reproduce the same behaviour. Potentially, it might also be a manifestation of some underlying NAS issue vaguely related to locking/replication.

    0 讨论(0)
  • 2020-12-04 07:13

    In my case, I was trying to execute a shell file (with an extension .sh) in a csh environment, and I was getting that error message.

    just running with bash it worked for me. For example

    bash file.sh

    0 讨论(0)
  • 2020-12-04 07:18

    Don't know the cause but I can contribute a quick and easy work around.

    I just experienced this this oddity on CentOS 6 after cat > shScript.sh (paste, ^Z) then editing the file in KWrite. Oddly there was no discernible instance (ps -ef) of the script executing.

    My quick work around was simply to cp shScript.sh shScript2.sh then I was able to execute shScript2.sh. Then I deleted both. Done!

    0 讨论(0)
  • 2020-12-04 07:19

    Minimal runnable C POSIX reproduction example

    I recommend understanding the underlying API to better see what is going on.

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

    Compile and run:

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

    busy.out passes the asserts, and perror outputs:

    Text file busy
    

    so we deduce that the message is hardcoded in glibc itself.

    Alternatively:

    echo asdf > sleep.out
    

    makes Bash output:

    -bash: sleep.out: Text file busy
    

    For a more complex application, you can also observe it with strace:

    strace ./busy.out
    

    which contains:

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

    Tested on Ubuntu 18.04, Linux kernel 4.15.0.

    The error does not happen if you unlink first

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

    Then compile and run analogously to the above, and those asserts pass.

    This explains why it works for certain programs but not others. E.g. if you do:

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

    that does not generate an error, even though the second gcc call is writing to sleep.out.

    A quick strace shows that GCC first unlinks before writing:

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

    contains:

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

    The reason it does not fail is that when you unlink and re-write the file, it creates a new inode, and keeps a temporary dangling inode for the running executable file.

    But if you just write without unlink, then it tries to write to the same protected inode as the running executable.

    POSIX 7 open()

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

    [ETXTBSY]

    The file is a pure procedure (shared text) file that is being executed and oflag is O_WRONLY or O_RDWR.

    man 2 open

    ETXTBSY

    pathname refers to an executable image which is currently being executed and write access was requested.

    glibc source

    A quick grep on 2.30 gives:

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

    and a manual hit in 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
    
    0 讨论(0)
提交回复
热议问题