14

From the Unix Power Tools, 3rd Edition: Instead of Removing a File, Empty It section:

If an active process has the file open (not uncommon for log files), removing the file and creating a new one will not affect the logging program; those messages will just keep going to the file that’s no longer linked. Emptying the file doesn’t break the association, and so it clears the file without affecting the logging program.

(emphasis mine)

I don't understand why a program will continue to log to a deleted file. Is it because the file descriptor entry not getting removed from the process table?

Geek
  • 6,688

3 Answers3

15

When you delete a file you really remove a link to the file (to the inode). If someone already has that file open, they get to keep the file descriptor they have. The file remains on disk, taking up space, and can be written to and read from if you have access to it.

The unlink function is defined with this behaviour by POSIX:

When the file's link count becomes 0 and no process has the file open, the space occupied by the file shall be freed and the file shall no longer be accessible. If one or more processes have the file open when the last link is removed, the link shall be removed before unlink() returns, but the removal of the file contents shall be postponed until all references to the file are closed.

This piece of advice because of that behaviour. The daemon will have the file open, and won't notice that it has been deleted (unless it was monitoring it specifically, which is uncommon). It will keep blithely writing to the existing file descriptor it has: you'll keep taking up (more) space on disk, but you won't be able to see any of the messages it writes, so you're really in the worst of both worlds. If you truncate the file to zero length instead then the space is freed up immediately, and any new messages will be appended at the new end of the file where you can see them.

Eventually, when the daemon terminates or closes the file, the space will be freed up. Nobody new can open the file in the mean time (other than through system-specific reflective interfaces like Linux's /proc/x/fd/...). It's also guaranteed that:

If the link count of the file is 0, when all file descriptors associated with the file are closed, the space occupied by the file shall be freed and the file shall no longer be accessible.

So you don't lose your disk space permanently, but you don't gain anything by deleting the file and you lose access to new messages.

Michael Homer
  • 76,565
  • 1
    What will occur if a user (let's say root here) attempt to unlink /proc/x/fd/y? Would that cause the process to fail to write to the file descriptor, or is that an illegal operation? – nanofarad Jul 28 '14 at 11:11
  • @hexafraction /proc/*/fd/* are symlinks to real files, so removing them won't delete the file. I'd suggest you to experiment :) (not on production system of course!) – Ruslan Jul 28 '14 at 11:19
  • 1
    @MichaelHomer Perhaps you could clarify in your answer that once a file is unlinked, the process having a file descriptor pointing to it can link it again, at the same path or not. This can sometimes be useful. – lgeorget Jul 28 '14 at 14:08
  • @hexafraction Well, these are just representations (in the filesystem space) of process state and objects. If you remove those representations in the filesystem space, nothing should happen to the actual process - unless it (or some other process) relies on that representation being there. Not sure you can use rm incontinently inside /proc or /sys without getting told off by the system anyway. – David Tonhofer Jul 28 '14 at 17:54
  • @lgeorget How is that accomplished? – Michael Jul 28 '14 at 18:30
  • @Michael Actually, this is not trivial, and not as portable as it should be. It can be done with the linkat(2) system call and the /proc/[pid]/fd/ directory. See http://stackoverflow.com/a/4174216 for reference. – lgeorget Jul 28 '14 at 21:40
  • @lgeorget Thanks for the link. Unfortunately, anything using /proc is quite un-portable and I was hoping for something which would run under non-Linux Unix variants... looks like there really isn't anything. – Michael Jul 29 '14 at 00:08
  • @Michael Unfortunately not... :-( Actually, I thought there was a portable standardized way to do it, something like a flink system call. Turns out I was wrong.

    The only portable way to do it is to link the file to a private location, unlink it from its original location, write to it, and finally link it back where it belongs. Of course, that's really different from what I said previously.

    – lgeorget Jul 29 '14 at 10:24
  • see also https://superuser.com/questions/283102/how-to-recover-deleted-file-if-it-is-still-opened-by-some-process – weberjn Jul 24 '18 at 21:23
8

Exactly.

Files are tri-partite.

  • The content, that is, a flat array of bytes, written somewhere on a disk or generated on-the-fly.
  • The index node, or inode for short, which is a data structure populated and used by the kernel. It contains all the metadata (size, permission, etc.) about the file, and also pointers to the location of the content of the file.
  • One or more directory entries, which are locations, manipulated as paths like /home/user/personal_file, which act as handles through which you can use the file, modify its content, change its metadata, etc.

When you open a file, you give the path to the operating system and it returns you a handle directly to the inode. With this handle, called a file descriptor, you can manipulate the file as you want (or at least, as permitted by the OS).

You can never delete directly an inode, you have to give a path to the OS to require deletion. So, when you want to delete a file, you delete only the directory entry. If the file has other directory entries, it will continue to be accessible, and even if it has not, its inode will not be deleted while there are still file descriptors pointing to it. @MichaelHomer's answer is more technical and more detailed on this specific topic.

lgeorget
  • 13,914
4

The other 2 answers explain the issue well - a file doesn't get "deleted" until all directory links to it and all open file descriptors to it are gone.

To avoid this, it's a good habit to use

> /var/log/bigfile

instead of

rm -f /var/log/bigfile

since that just resets the content to 0 bytes instead of deleting it, and you can still see what's written to it.

If you deleted the file, and are on linux where you have a /proc/fd filesystem, you can still use

> /proc/12345/fd/3

to zero the file's contents (assuming 12345 is your process id and 3 is the fd number of the big file). This can be a life saver if your disk is running full and you can't kill the process that's writing your log file for some reason.

  • > /var/log/bigfile removes the existing data in the file but doesn't stop programs from writing there. There are very few circumstances where it's the right thing. I'd say it's a bad habit to get into. If you want to delete a file, use rm. If you want to stop programs that are writing there, kill them or otherwise make them stop writing, before or after deleting. – Gilles 'SO- stop being evil' Jul 28 '14 at 21:58
  • 1
    @Giles, this topic is about the fact that deleting won't help if a program still has the file open. And if your disk is full because some program misbehaves and syslogd fills /var/log/messages, > /var/log/messages is a much better option than killing syslogd. Of course, that shouldn't stop you from analyzing what the problem is in the first place. – Guntram Blohm Jul 29 '14 at 07:13