Truncating a file while it's being used (Linux)

后端 未结 13 2021
名媛妹妹
名媛妹妹 2020-12-05 01:54

I have a process that\'s writing a lot of data to stdout, which I\'m redirecting to a log file. I\'d like to limit the size of the file by occasionally copying the current

相关标签:
13条回答
  • 2020-12-05 02:34

    I had a similar problem and was unable to do a "tail -f" on the output of a script that was run from cron:

        * * * * * my_script >> /var/log/my_script.log 2>&1
    

    I fixed it by changing the stderr redirect:

        * * * * * my_script >> /var/log/my_script.log 2>/var/log/my_script.err
    
    0 讨论(0)
  • Try > file.


    Update regarding the comments: it works nicely for me:

    robert@rm:~> echo "content" > test-file
    robert@rm:~> cat test-file 
    content
    robert@rm:~> > test-file
    robert@rm:~> cat test-file 
    
    0 讨论(0)
  • 2020-12-05 02:35

    In Linux (actually all unicies) files are created when they are opened and deleted when nothing holds a reference to them. In this case the program that opened it and the directory it was opened 'in' hold references to the file. When the cp program wants to write to the file it gets a reference to it from the directory, writes a length of zero into the metadata stored in the directory (this is a slight simplification) and gives up the handle. Then the original program, still holding the original file handle, writes some more data to the file and saves what it thinks the length should be.

    even if you where to delete the file from the directory the program would continue to write data to it (and use up disc space) even though no other program would have any way of referencing it.

    in short once the program has a reference (handle) to a file nothing you do is going to change that.

    there are in theory ways of modifying the programs behavior by setting LD_LIBRARY_PATH to include a program that intercepts all the file access system calls. I recall seeing something like this somewhere though cant recall the name.

    0 讨论(0)
  • 2020-12-05 02:35

    Did you check the behavior of any signals like SIGHUP to the third party product, to see if it will start logging a fresh file? You would move the old file to a permanent name, first.

    kill -HUP [process-id]

    And then it would start writing out again.

    Alternatively (as Billy suggested) maybe redirecting the output from the application to a logging program like multilog or the one that is commonly used with Apache, known as cronolog. Then you'll have more fine grained control of where everything goes before it is written to that initial file descriptor (file), which is really all it is.

    0 讨论(0)
  • 2020-12-05 02:36

    instead of redirecting it to a file you could pipe it to a program that automatically rotates the file by closing it, moving it and opening a new one every time it gets too big.

    0 讨论(0)
  • 2020-12-05 02:39

    The interesting thing about those regrown files is that the first 128 KB or so will be all zeroes after you truncate the file by copying /dev/null over it. This happens because the file is truncated to zero length, but the file descriptor in the application still points immediately after its last write. When it writes again, the file system treats the start of the file as all zero bytes - without actually writing the zeroes to disk.

    Ideally, you should ask the vendor of the application to open the log file with the O_APPEND flag. This means that after you truncate the file, the next write will implicitly seek to the end of the file (meaning back to offset zero) and then write the new information.


    This code rigs standard output so it is in O_APPEND mode and then invokes the command given by its arguments (rather like nice runs a command after adjusting its nice-level, or nohup runs a command after fixing things so it ignores SIGHUP).

    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <string.h>
    #include <errno.h>
    
    static char *arg0 = "<unknown>";
    
    static void error(const char *fmt, ...)
    {
        va_list args;
        int errnum = errno;
        fprintf(stderr, "%s: ", arg0);
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        if (errnum != 0)
            fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
        putc('\n', stderr);
        fflush(0);
        exit(1);
    }
    
    int main(int argc, char **argv)
    {
        int attr;
        arg0 = argv[0];
    
        if (argc < 2)
            error("Usage: %s cmd [arg ...]", arg0);
        if ((attr = fcntl(1, F_GETFL, &attr)) < 0)
            error("fcntl(F_GETFL) failed");
        attr |= O_APPEND;
        if (fcntl(1, F_SETFL, attr) != 0)
            error("fcntl(F_SETFL) failed");
        execvp(argv[1], &argv[1]);
        error("failed to exec %s", argv[1]);
        return(1);
    }
    

    My testing of it was somewhat casual, but just barely enough to persuade me that it worked.


    Simpler alternative

    Billy notes in his answer that '>>' is the append operator - and indeed, on Solaris 10, bash (version 3.00.16(1)) does use the O_APPEND flag - thereby making the code above unnecessary, as shown ('Black JL:' is my prompt on this machine):

    Black JL: truss -o bash.truss bash -c "echo Hi >> x3.29"
    Black JL: grep open bash.truss
    open("/var/ld/ld.config", O_RDONLY)             Err#2 ENOENT
    open("/usr/lib/libcurses.so.1", O_RDONLY)       = 3
    open("/usr/lib/libsocket.so.1", O_RDONLY)       = 3
    open("/usr/lib/libnsl.so.1", O_RDONLY)          = 3
    open("/usr/lib/libdl.so.1", O_RDONLY)           = 3
    open("/usr/lib/libc.so.1", O_RDONLY)            = 3
    open("/platform/SUNW,Ultra-4/lib/libc_psr.so.1", O_RDONLY) = 3
    open64("/dev/tty", O_RDWR|O_NONBLOCK)           = 3
    stat64("/usr/openssl/v0.9.8e/bin/bash", 0xFFBFF2A8) Err#2 ENOENT
    open64("x3.29", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3
    Black JL:
    

    Use append redirection rather than the wrapper ('cantrip') code above. This just goes to show that when you use one particular technique for other (valid) purposes, adapting it to yet another is not necessarily the simplest mechanism - even though it works.

    0 讨论(0)
提交回复
热议问题